1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.testutils 18 19 import android.net.Uri 20 import com.android.net.module.util.ArrayTrackRecord 21 import fi.iki.elonen.NanoHTTPD 22 23 /** 24 * A minimal HTTP server running on a random available port. 25 * 26 * @param host The host to listen to, or null to listen on all hosts 27 */ 28 class TestHttpServer(host: String? = null) : NanoHTTPD(host, 0 /* auto-select the port */) { 29 // Map of URL path -> HTTP response code 30 private val responses = HashMap<Request, Response>() 31 32 /** 33 * A record of all requests received by the server since it was started. 34 */ 35 val requestsRecord = ArrayTrackRecord<Request>() 36 37 /** 38 * A request received by the test server. 39 */ 40 data class Request( 41 val path: String, 42 val method: Method = Method.GET, 43 val queryParameters: String = "" 44 ) { 45 /** 46 * Returns whether the specified [Uri] matches parameters of this request. 47 */ 48 fun matches(uri: Uri) = (uri.path ?: "") == path && (uri.query ?: "") == queryParameters 49 } 50 51 /** 52 * Add a response for GET requests with the path and query parameters of the specified [Uri]. 53 */ 54 fun addResponse( 55 uri: Uri, 56 statusCode: Response.IStatus, 57 headers: Map<String, String>? = null, 58 content: String = "" 59 ) { 60 addResponse(Request(uri.path 61 ?: "", Method.GET, uri.query ?: ""), 62 statusCode, headers, content) 63 } 64 65 /** 66 * Add a response for the given request. 67 */ 68 fun addResponse( 69 request: Request, 70 statusCode: Response.IStatus, 71 headers: Map<String, String>? = null, 72 content: String = "" 73 ) { 74 val response = newFixedLengthResponse(statusCode, "text/plain", content) 75 headers?.forEach { 76 (key, value) -> response.addHeader(key, value) 77 } 78 responses[request] = response 79 } 80 81 override fun serve(session: IHTTPSession): Response { 82 val request = Request(session.uri 83 ?: "", session.method, session.queryParameterString ?: "") 84 requestsRecord.add(request) 85 // Default response is a 404 86 return responses[request] ?: super.serve(session) 87 } 88 }