-
Notifications
You must be signed in to change notification settings - Fork 412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor: Merge client and server Request
#894
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,37 @@ | ||
package zhttp.service | ||
|
||
import io.netty.buffer.Unpooled | ||
import io.netty.handler.codec.http.{DefaultFullHttpRequest, FullHttpRequest, HttpHeaderNames, HttpVersion} | ||
import zhttp.http.HTTP_CHARSET | ||
import zhttp.http.Request | ||
import zio.Task | ||
trait EncodeClientParams { | ||
|
||
/** | ||
* Converts client params to JFullHttpRequest | ||
*/ | ||
def encodeClientParams(jVersion: HttpVersion, req: Client.ClientRequest): FullHttpRequest = { | ||
val method = req.method.asHttpMethod | ||
val url = req.url | ||
|
||
// As per the spec, the path should contain only the relative path. | ||
// Host and port information should be in the headers. | ||
val path = url.relative.encode | ||
|
||
val content = req.getBodyAsString match { | ||
case Some(text) => Unpooled.copiedBuffer(text, HTTP_CHARSET) | ||
case None => Unpooled.EMPTY_BUFFER | ||
} | ||
|
||
val encodedReqHeaders = req.getHeaders.encode | ||
|
||
val headers = url.host match { | ||
case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) | ||
case None => encodedReqHeaders | ||
} | ||
|
||
val writerIndex = content.writerIndex() | ||
if (writerIndex != 0) { | ||
headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) | ||
} | ||
// TODO: we should also add a default user-agent req header as some APIs might reject requests without it. | ||
val jReq = new DefaultFullHttpRequest(jVersion, method, path, content) | ||
jReq.headers().set(headers) | ||
|
||
jReq | ||
def encodeClientParams(jVersion: HttpVersion, req: Request): Task[FullHttpRequest] = req.getBodyAsByteBuf.map { | ||
content => | ||
val method = req.method.asHttpMethod | ||
val url = req.url | ||
|
||
// As per the spec, the path should contain only the relative path. | ||
// Host and port information should be in the headers. | ||
val path = url.relative.encode | ||
|
||
val encodedReqHeaders = req.getHeaders.encode | ||
|
||
val headers = url.host match { | ||
case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) | ||
case None => encodedReqHeaders | ||
} | ||
|
||
val writerIndex = content.writerIndex() | ||
if (writerIndex != 0) { | ||
headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) | ||
} | ||
// TODO: we should also add a default user-agent req header as some APIs might reject requests without it. | ||
val jReq = new DefaultFullHttpRequest(jVersion, method, path, content) | ||
jReq.headers().set(headers) | ||
|
||
jReq | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package zhttp.http | ||
|
||
import io.netty.handler.codec.http.{HttpHeaderNames, HttpVersion} | ||
import zhttp.internal.HttpGen | ||
import zhttp.service.EncodeClientParams | ||
import zio.random.Random | ||
import zio.test.Assertion._ | ||
import zio.test._ | ||
|
||
object EncodeRequestSpec extends DefaultRunnableSpec with EncodeClientParams { | ||
|
||
val anyClientParam: Gen[Random with Sized, Request] = HttpGen.clientRequest( | ||
HttpGen.httpData( | ||
Gen.listOf(Gen.alphaNumericString), | ||
), | ||
) | ||
|
||
val clientParamWithAbsoluteUrl = HttpGen.clientRequest( | ||
dataGen = HttpGen.httpData( | ||
Gen.listOf(Gen.alphaNumericString), | ||
), | ||
urlGen = HttpGen.genAbsoluteURL, | ||
) | ||
|
||
def clientParamWithFiniteData(size: Int): Gen[Random with Sized, Request] = HttpGen.clientRequest( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #nitpick Should we keep it HttpGen? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can keep it here for now, as this test is the only user of this Gen There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was already there, the file has been renamed only. |
||
for { | ||
content <- Gen.alphaNumericStringBounded(size, size) | ||
data <- Gen.fromIterable(List(HttpData.fromString(content))) | ||
} yield data, | ||
) | ||
|
||
def spec = suite("EncodeClientParams") { | ||
testM("method") { | ||
checkM(anyClientParam) { params => | ||
val method = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.method()) | ||
assertM(method)(equalTo(params.method.asHttpMethod)) | ||
} | ||
} + | ||
testM("method on HttpData.File") { | ||
checkM(HttpGen.clientParamsForFileHttpData()) { params => | ||
val method = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.method()) | ||
assertM(method)(equalTo(params.method.asHttpMethod)) | ||
} | ||
} + | ||
suite("uri") { | ||
testM("uri") { | ||
checkM(anyClientParam) { params => | ||
val uri = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.uri()) | ||
assertM(uri)(equalTo(params.url.relative.encode)) | ||
} | ||
} + | ||
testM("uri on HttpData.File") { | ||
checkM(HttpGen.clientParamsForFileHttpData()) { params => | ||
val uri = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.uri()) | ||
assertM(uri)(equalTo(params.url.relative.encode)) | ||
} | ||
} | ||
} + | ||
testM("content-length") { | ||
checkM(clientParamWithFiniteData(5)) { params => | ||
val len = encodeClientParams(HttpVersion.HTTP_1_1, params).map( | ||
_.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong, | ||
) | ||
assertM(len)(equalTo(5L)) | ||
} | ||
} + | ||
testM("host header") { | ||
checkM(anyClientParam) { params => | ||
val hostHeader = HttpHeaderNames.HOST | ||
val headers = encodeClientParams(HttpVersion.HTTP_1_1, params).map(h => Option(h.headers().get(hostHeader))) | ||
assertM(headers)(equalTo(params.url.host)) | ||
} | ||
} + | ||
testM("host header when absolute url") { | ||
checkM(clientParamWithAbsoluteUrl) { params => | ||
val hostHeader = HttpHeaderNames.HOST | ||
for { | ||
reqHeaders <- encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.headers()) | ||
} yield assert(reqHeaders.getAll(hostHeader).size)(equalTo(1)) && assert(Option(reqHeaders.get(hostHeader)))( | ||
equalTo(params.url.host), | ||
) | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#nitpick This as well?
candidate for HttpGen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can keep it here for now, as this test is the only user of this Gen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was already there, the file has been renamed only.