-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
kotlin: add library request interfaces (#240)
envoyproxy/envoy-mobile#119 Adding a primitive `Request` and `RequestBuilder` with basic features: * URL * method * headers * trailers * retry policy Tests are basic setting a builder and ensuring the result is expected. Additionally, the request build transform creates an equivalent object when built back. Signed-off-by: Alan Chiu <achiu@lyft.com> For an explanation of how to fill out the fields, please see the relevant section in [PULL_REQUESTS.md](https://github.com/envoyproxy/envoy/blob/master/PULL_REQUESTS.md) Description: kotlin: add library request interfaces Risk Level: low Testing: unit Docs Changes: n/a Release Notes: n/a [Optional Fixes #Issue] [Optional Deprecated:] Signed-off-by: JP Simard <jp@jpsim.com>
- Loading branch information
Showing
8 changed files
with
521 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
mobile/library/kotlin/src/io/envoyproxy/envoymobile/Request.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package io.envoyproxy.envoymobile | ||
|
||
import java.net.URL | ||
|
||
class Request internal constructor( | ||
val method: RequestMethod, | ||
val url: URL, | ||
val headers: Map<String, List<String>>, | ||
val trailers: Map<String, List<String>>, | ||
val body: ByteArray?, | ||
val retryPolicy: RetryPolicy? | ||
) { | ||
|
||
/** | ||
* Transforms this Request to the {@link io.envoyproxy.envoymobile.RequestBuilder} for modification using the | ||
* current properties | ||
* | ||
* @return the builder | ||
*/ | ||
fun toBuilder(): RequestBuilder { | ||
return RequestBuilder(url, method) | ||
.setHeaders(headers) | ||
.setTrailers(trailers) | ||
.addBody(body) | ||
.addRetryPolicy(retryPolicy) | ||
} | ||
|
||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (javaClass != other?.javaClass) return false | ||
|
||
other as Request | ||
|
||
if (method != other.method) return false | ||
if (url != other.url) return false | ||
if (headers != other.headers) return false | ||
if (trailers != other.trailers) return false | ||
if (body != null) { | ||
if (other.body == null) return false | ||
if (!body.contentEquals(other.body)) return false | ||
} else if (other.body != null) return false | ||
if (retryPolicy != other.retryPolicy) return false | ||
|
||
return true | ||
} | ||
|
||
override fun hashCode(): Int { | ||
var result = method.hashCode() | ||
result = 31 * result + url.hashCode() | ||
result = 31 * result + headers.hashCode() | ||
result = 31 * result + trailers.hashCode() | ||
result = 31 * result + (body?.contentHashCode() ?: 0) | ||
result = 31 * result + (retryPolicy?.hashCode() ?: 0) | ||
return result | ||
} | ||
} |
170 changes: 170 additions & 0 deletions
170
mobile/library/kotlin/src/io/envoyproxy/envoymobile/RequestBuilder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
package io.envoyproxy.envoymobile | ||
|
||
import java.net.URL | ||
|
||
|
||
/** | ||
* Builder used for constructing instances of `Request` types. | ||
* | ||
* @param url URL for the request. | ||
* @param method Method for the request. | ||
*/ | ||
class RequestBuilder( | ||
val url: URL, | ||
val method: RequestMethod | ||
) { | ||
// Headers to send with the request. | ||
// Multiple values for a given name are valid, and will be sent as comma-separated values. | ||
private val headers: MutableMap<String, MutableList<String>> = mutableMapOf() | ||
|
||
// Trailers to send with the request. | ||
// Multiple values for a given name are valid, and will be sent as comma-separated values. | ||
private val trailers: MutableMap<String, MutableList<String>> = mutableMapOf() | ||
|
||
// Serialized data to send as the body of the request. | ||
private var body: ByteArray? = null | ||
|
||
// Retry policy to use for this request. | ||
private var retryPolicy: RetryPolicy? = null | ||
|
||
/** | ||
* Serialized data to send as the body of the request. | ||
*/ | ||
fun addBody(body: ByteArray?): RequestBuilder { | ||
this.body = body | ||
return this | ||
} | ||
|
||
/** | ||
* Add a retry policy to use for this request. | ||
* | ||
* @param retryPolicy the {@link io.envoyproxy.envoymobile.RetryPolicy} for this request. | ||
* @return this builder. | ||
*/ | ||
fun addRetryPolicy(retryPolicy: RetryPolicy?): RequestBuilder { | ||
this.retryPolicy = retryPolicy | ||
return this | ||
} | ||
|
||
/** | ||
* Append a value to the header key. | ||
* | ||
* @param name the header key. | ||
* @param value the value associated to the header key. | ||
* @return this builder. | ||
*/ | ||
fun addHeader(name: String, value: String): RequestBuilder { | ||
if (headers.containsKey(name)) { | ||
headers[name]!!.add(value) | ||
} else { | ||
headers[name] = mutableListOf(value) | ||
} | ||
return this | ||
} | ||
|
||
/** | ||
* Remove the value in the specified header. | ||
* | ||
* @param name the header key to remove. | ||
* @param value the value to be removed. | ||
* @return this builder. | ||
*/ | ||
fun removeHeader(name: String, value: String): RequestBuilder { | ||
if (headers.containsKey(name)) { | ||
headers[name]!!.remove(value) | ||
if (headers[name]!!.isEmpty()) { | ||
headers.remove(name) | ||
} | ||
} | ||
return this | ||
} | ||
|
||
/** | ||
* Remove all headers with this name. | ||
* | ||
* @param name the header key to remove. | ||
* @return this builder. | ||
*/ | ||
fun removeHeaders(name: String): RequestBuilder { | ||
headers.remove(name) | ||
return this | ||
} | ||
|
||
/** | ||
* Append a value to the trailer key. | ||
* | ||
* @param name the trailer key. | ||
* @param value the value associated to the trailer key. | ||
* @return this builder. | ||
*/ | ||
fun addTrailer(name: String, value: String): RequestBuilder { | ||
if (trailers.containsKey(name)) { | ||
trailers[name]!!.add(value) | ||
} else { | ||
trailers[name] = mutableListOf(value) | ||
} | ||
return this | ||
} | ||
|
||
/** | ||
* Remove the value in the specified trailer. | ||
* | ||
* @param name the trailer key to remove. | ||
* @param value the value to be removed. | ||
* @return this builder. | ||
*/ | ||
fun removeTrailers(name: String): RequestBuilder { | ||
trailers.remove(name) | ||
return this | ||
} | ||
|
||
/** | ||
* Remove the value in the specified trailer. | ||
* | ||
* @param name the trailer key to remove. | ||
* @param value the value to be removed. | ||
* @return this builder. | ||
*/ | ||
fun removeTrailer(name: String, value: String): RequestBuilder { | ||
if (trailers.containsKey(name)) { | ||
trailers[name]!!.remove(value) | ||
|
||
if (trailers[name]!!.isEmpty()) { | ||
trailers.remove(name) | ||
} | ||
} | ||
return this | ||
} | ||
|
||
/** | ||
* Creates the {@link io.envoyproxy.envoymobile.Request} object using the data set in the builder | ||
* | ||
* @return the {@link io.envoyproxy.envoymobile.Request} object | ||
*/ | ||
fun build(): Request { | ||
return Request( | ||
method, | ||
url, | ||
headers, | ||
trailers, | ||
body, | ||
retryPolicy | ||
) | ||
} | ||
|
||
internal fun setHeaders(headers: Map<String, List<String>>): RequestBuilder { | ||
this.headers.clear() | ||
for (entry in headers) { | ||
this.headers[entry.key] = entry.value.toMutableList() | ||
} | ||
return this | ||
} | ||
|
||
internal fun setTrailers(trailers: Map<String, List<String>>): RequestBuilder { | ||
this.trailers.clear() | ||
for (entry in trailers) { | ||
this.trailers[entry.key] = entry.value.toMutableList() | ||
} | ||
return this | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
mobile/library/kotlin/src/io/envoyproxy/envoymobile/RequestMethod.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package io.envoyproxy.envoymobile | ||
|
||
/** | ||
* Represents an HTTP request method. | ||
*/ | ||
enum class RequestMethod { | ||
DELETE, | ||
GET, | ||
HEAD, | ||
OPTIONS, | ||
PATCH, | ||
POST, | ||
PUT, | ||
TRACE | ||
} |
26 changes: 26 additions & 0 deletions
26
mobile/library/kotlin/src/io/envoyproxy/envoymobile/RetryPolicy.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package io.envoyproxy.envoymobile | ||
|
||
/** | ||
* Specifies how a request may be retried, containing one or more rules. | ||
* | ||
* @param maxRetryCount Maximum number of retries that a request may be performed. | ||
* @param retryOn Whitelist of rules used for retrying. | ||
* @param perRetryTimeoutMs Timeout (in milliseconds) to apply to each retry. | ||
*/ | ||
data class RetryPolicy( | ||
val maxRetryCount: Int, | ||
val retryOn: List<RetryRule>, | ||
val perRetryTimeoutMs: Long? | ||
) | ||
|
||
/** | ||
* These are retry rules specified in Envoy's router filter. | ||
* @see <a href="https://www.envoyproxy.io/docs/envoy/latest/configuration/http_filters/router_filter#x-envoy-retry-on">x-envoy-retry-on</a> | ||
*/ | ||
enum class RetryRule { | ||
FIVE_XX, | ||
GATEWAY_ERROR, | ||
CONNECT_FAILURE, | ||
RETRIABLE_FOUR_XX, | ||
REFUSED_UPSTREAM, | ||
} |
26 changes: 26 additions & 0 deletions
26
mobile/library/kotlin/test/io/envoyproxy/envoymobile/BUILD
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
licenses(["notice"]) # Apache 2 | ||
|
||
load("@envoy//bazel:envoy_build_system.bzl", "envoy_package") | ||
load("//bazel:kotlin_test.bzl", "envoy_mobile_kt_test") | ||
|
||
envoy_package() | ||
|
||
envoy_mobile_kt_test( | ||
name = "request_builder_test", | ||
srcs = [ | ||
"RequestBuilderTest.kt", | ||
], | ||
deps = [ | ||
"//library/kotlin/src/io/envoyproxy/envoymobile:envoy_interfaces_lib", | ||
], | ||
) | ||
|
||
envoy_mobile_kt_test( | ||
name = "request_test", | ||
srcs = [ | ||
"RequestTest.kt", | ||
], | ||
deps = [ | ||
"//library/kotlin/src/io/envoyproxy/envoymobile:envoy_interfaces_lib", | ||
], | ||
) |
Oops, something went wrong.