
org.organicdesign.testUtils.http.FakeHttpServletRequest.kt Maven / Gradle / Ivy
package org.organicdesign.testUtils.http
import org.organicdesign.indented.IndentedStringable
import org.organicdesign.indented.StringUtils.spaces
import org.organicdesign.indented.StringUtils.stringify
import org.organicdesign.indented.StringUtils.indent
import java.io.BufferedReader
import java.security.Principal
import java.util.*
import javax.servlet.*
import javax.servlet.http.*
import java.io.IOException
import java.io.InputStream
import java.lang.Exception
/**
* This mocks an HttpServletRequest - EXPERIMENTAL
*/
class FakeHttpServletRequest
internal constructor(
reqB: ReqB
) : HttpServletRequest, IndentedStringable {
override fun indentedStr(indent:Int):String {
val sB = java.lang.StringBuilder("FakeHttpServletRequest(\n")
.append("${spaces(indent + 8)}url=${stringify(requestURL.toString())},\n")
.append("${spaces(indent + 8)}remoteAddr=${stringify(remoteAddr)},\n")
.append("${spaces(indent + 8)}method=${stringify(method)},\n")
if (characterEncoding != null) {
sB.append("${spaces(indent + 8)}encoding=${stringify(characterEncoding)},\n")
}
if (locale != null) {
sB.append("${spaces(indent + 8)}locale=$locale,\n")
}
if (requestedSessionId != null) {
sB.append("${spaces(indent + 8)}requestedSessionId=${stringify(requestedSessionId)},\n")
}
sB.append("${spaces(indent + 8)}inputStream=$inStream,\n" +
"${spaces(indent + 8)}attributes=${indent(indent + 19, attributes)},\n" +
"${spaces(indent + 8)}cookies=${indent(indent + 16, cookies.map { CookiePrinter(it) })},\n" +
"${spaces(indent + 8)}params=${indent(indent + 15, params)},\n" +
"${spaces(indent + 8)}headers=${indent(indent + 16, heads)},\n" +
"${spaces(indent)})")
return sB.toString()
}
override fun toString(): String = indentedStr(0)
private val baseUrl: String = reqB.baseUrl
// TODO: What about nulls? Also, Needs to return a Protocol, server name, port num, and server path (but no query string)
override fun getRequestURL(): StringBuffer {
val sB = StringBuffer(baseUrl)
if (uri != null) {
sB.append(uri)
}
return sB
}
private val uri: String? = reqB.uri
// 2018-03-02: Tomcat 8 can return null here. Jetty does not.
override fun getPathInfo(): String? = uri
override fun getRequestURI(): String? = uri
// TODO: Not sure if this always starts with a slash or not, but maybe can't be null?
override fun getServletPath(): String? = uri
// Looks like an IP address
// My code elsewhere assumes that this can never be null, so I'm going with that, at least for Jetty.
private val remoteAddr = reqB.remoteAddr
override fun getRemoteAddr(): String = remoteAddr
private val method: String = reqB.method
override fun getMethod(): String = method
private var characterEncoding: String? = reqB.characterEncoding
override fun getCharacterEncoding(): String? = characterEncoding
override fun setCharacterEncoding(s: String?) { characterEncoding = s }
private val locale: Locale? = reqB.locale
// TODO: Can this be null?
override fun getLocale(): Locale? = locale
// TODO: locales that are acceptable to the client based on the Accept-Language header.
override fun getLocales(): Enumeration =
enumeration(listOf(locale))
private val requestedSessionId: String? = reqB.requestedSessionId
override fun getRequestedSessionId(): String? = requestedSessionId
private val inStream = reqB.inStream
private val inStreamSize = reqB.inStreamSize
override fun getInputStream(): ServletInputStream? =
if (inStream == null) {
null
} else {
FakeServletInputStream(inStream)
}
override fun getContentLength(): Int =
if (inStreamSize > Int.MAX_VALUE) {
-1
} else {
inStreamSize.toInt()
}
override fun getContentLengthLong(): Long = inStreamSize
private val attributes: MutableMap = reqB.attributes
override fun getAttribute(s: String): Any? = attributes[s]
override fun getAttributeNames(): Enumeration = enumeration(attributes.keys)
override fun setAttribute(s: String, o: Any) { attributes[s] = o }
override fun removeAttribute(s: String) { attributes.remove(s) }
private val params: Map> = reqB.params.toMap()
override fun getParameterNames(): Enumeration = enumeration(params.keys)
override fun getParameterValues(s: String): Array? = params[s]?.toTypedArray()
override fun getParameter(s: String): String? = getParameterValues(s)?.get(0)
override fun getParameterMap(): Map> {
val ret: MutableMap> = mutableMapOf()
for (entry in params.entries) {
ret[entry.key] = entry.value.toTypedArray()
}
return ret
}
override fun getQueryString(): String? {
val sB = StringBuilder()
for ((key, value) in params) {
for (v in value) {
sB.append(if (sB.isNotEmpty()) "&" else "")
.append(key).append("=")
.append(v)
}
}
return sB.toString()
}
// HTTP headers are case-insensitive.
// https://stackoverflow.com/questions/8236945/case-insensitive-string-as-hashmap-key
// For case insensitive hack:
// https://stackoverflow.com/questions/8236945/case-insensitive-string-as-hashmap-key
// Actual implementation in Jetty uses an *array*.
private val heads: Array> = when {
reqB.headers.any{ HTTP_HEAD_HOST.equals(it.key, ignoreCase = true) } -> reqB.headers.toTypedArray()
else -> {
val hs = reqB.headers.toMutableList()
hs.add(Kv(HTTP_HEAD_HOST, reqB.baseUrl.substringAfter("//")))
hs.toTypedArray()
}
}
override fun getHeader(p0: String?): String? {
if (p0 != null) {
for (head in heads) {
if (p0.equals(head.key, ignoreCase = true)) {
return head.value
}
}
}
return null
}
override fun getHeaders(s: String?): Enumeration? {
val header = getHeader(s)
return if (header == null) null else enumeration(listOf(header))
}
override fun getHeaderNames(): Enumeration {
return enumeration(heads.map { it.key }.toList())
}
override fun getIntHeader(s: String): Int =
try {
Integer.parseInt(getHeader(s))
} catch (_: Exception) {
-1
}
override fun getDateHeader(p0: String?): Long {
return getHeader(p0)?.toLong() ?: -1
}
override fun getContentType(): String? = getHeader("Content-Type")
private val cookies: MutableList = reqB.cookies
override fun getCookies(): Array? =
when {
cookies.isEmpty() -> null
else -> cookies.toTypedArray()
}
override fun getAuthType(): String {
throw UnsupportedOperationException("Not Implemented")
}
override fun getPathTranslated(): String? {
throw UnsupportedOperationException("Not implemented")
}
override fun getContextPath(): String {
throw UnsupportedOperationException("Not implemented")
}
override fun getRemoteUser(): String {
throw UnsupportedOperationException("Not implemented")
}
override fun isUserInRole(s: String): Boolean {
throw UnsupportedOperationException("Not implemented")
}
override fun getUserPrincipal(): Principal {
throw UnsupportedOperationException("Not implemented")
}
override fun getSession(b: Boolean): HttpSession {
throw UnsupportedOperationException("Not implemented")
}
override fun getSession(): HttpSession {
throw UnsupportedOperationException("Not implemented")
}
override fun changeSessionId(): String {
throw UnsupportedOperationException("Not implemented")
}
override fun isRequestedSessionIdValid(): Boolean {
throw UnsupportedOperationException("Not implemented")
}
override fun isRequestedSessionIdFromCookie(): Boolean {
throw UnsupportedOperationException("Not implemented")
}
override fun isRequestedSessionIdFromURL(): Boolean {
throw UnsupportedOperationException("Not implemented")
}
@Deprecated("")
override fun isRequestedSessionIdFromUrl(): Boolean {
throw UnsupportedOperationException("Not implemented")
}
override fun authenticate(httpServletResponse: HttpServletResponse): Boolean {
throw UnsupportedOperationException("Not implemented")
}
override fun login(s: String, s1: String) {
throw UnsupportedOperationException("Not implemented")
}
override fun logout() {
throw UnsupportedOperationException("Not implemented")
}
override fun getParts(): Collection {
throw UnsupportedOperationException("Not implemented")
}
override fun getPart(s: String): Part {
throw UnsupportedOperationException("Not implemented")
}
override fun upgrade(aClass: Class): T {
throw UnsupportedOperationException("Not implemented")
}
override fun getProtocol(): String? {
throw UnsupportedOperationException("Not implemented")
}
override fun getScheme(): String = baseUrl.substringBefore("://")
override fun getServerName(): String = getHeader(HTTP_HEAD_HOST)!!.substringBefore(":")
override fun getServerPort(): Int {
val host: String = getHeader(HTTP_HEAD_HOST)!!
return when {
host.contains(":") -> host.substringAfter(":").toInt()
else -> schemePorts.getOrDefault(scheme, 0)
}
}
override fun getReader(): BufferedReader {
throw UnsupportedOperationException("Not implemented")
}
override fun getRemoteHost(): String {
throw UnsupportedOperationException("Not implemented")
}
override fun isSecure(): Boolean {
throw UnsupportedOperationException("Not implemented")
}
override fun getRequestDispatcher(s: String): RequestDispatcher {
throw UnsupportedOperationException("Not implemented")
}
@Deprecated("")
override fun getRealPath(s: String): String {
throw UnsupportedOperationException("Not implemented")
}
override fun getRemotePort(): Int {
throw UnsupportedOperationException("Not implemented")
}
override fun getLocalName(): String {
throw UnsupportedOperationException("Not implemented")
}
override fun getLocalAddr(): String {
throw UnsupportedOperationException("Not implemented")
}
override fun getLocalPort(): Int {
throw UnsupportedOperationException("Not implemented")
}
override fun getServletContext(): ServletContext {
throw UnsupportedOperationException("Not implemented")
}
@Throws(IllegalStateException::class)
override fun startAsync(): AsyncContext {
throw UnsupportedOperationException("Not implemented")
}
@Throws(IllegalStateException::class)
override fun startAsync(servletRequest: ServletRequest, servletResponse: ServletResponse): AsyncContext {
throw UnsupportedOperationException("Not implemented")
}
override fun isAsyncStarted(): Boolean {
throw UnsupportedOperationException("Not implemented")
}
override fun isAsyncSupported(): Boolean {
throw UnsupportedOperationException("Not implemented")
}
override fun getAsyncContext(): AsyncContext {
throw UnsupportedOperationException("Not implemented")
}
override fun getDispatcherType(): DispatcherType {
throw UnsupportedOperationException("Not implemented")
}
companion object {
const val HTTP_HEAD_HOST = "Host"
private val schemePorts: Map = mapOf("https" to 443,
"http" to 80,
"ftp" to 21)
fun enumeration(iterable: Iterable): Enumeration {
return object : Enumeration {
var iter = iterable.iterator()
override fun hasMoreElements(): Boolean {
return iter.hasNext()
}
override fun nextElement(): E {
return iter.next()
}
}
}
private class FakeServletInputStream(
private val inStream: InputStream
) : ServletInputStream() {
private var eosReached = false
override fun isReady(): Boolean = !eosReached
override fun isFinished(): Boolean = eosReached
override fun setReadListener(p0: ReadListener?) {
throw UnsupportedOperationException("Not Implemented")
}
@Throws(IOException::class)
override fun read(): Int {
val ret = inStream.read()
if (ret == -1) {
eosReached = true
}
return ret
}
@Throws(IOException::class)
override fun read(b: ByteArray, off: Int, len: Int): Int {
val ret = inStream.read(b, off, len)
if (ret == -1) {
eosReached = true
}
return ret
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy