Upgraded dependencies, and simplified response output stream.
Build and Test Module / build-and-test (push) Successful in 11s Details

This commit is contained in:
Andrew Lalis 2025-03-05 20:13:45 -05:00
parent b260ddfe8c
commit 4d352a0ffa
5 changed files with 71 additions and 27 deletions

19
.gitea/workflows/ci.yaml Normal file
View File

@ -0,0 +1,19 @@
name: Build and Test Module
on:
push:
paths:
- 'source/**'
- '.gitea/workflows/ci.yaml'
pull_request:
types: [opened, reopened, synchronize]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup DLang
uses: dlang-community/setup-dlang@v2
with:
compiler: ldc-latest
- name: Build and Test
run: dub -q test

View File

@ -4,9 +4,9 @@
], ],
"copyright": "Copyright © 2024, Andrew Lalis", "copyright": "Copyright © 2024, Andrew Lalis",
"dependencies": { "dependencies": {
"handy-http-primitives": "~>1.0.0", "handy-http-primitives": "~>1",
"photon": "~>0.10.2", "photon": "~>0.10.2",
"streams": "~>3.5.0" "streams": "~>3"
}, },
"description": "Implementations of HTTP transport protocols.", "description": "Implementations of HTTP transport protocols.",
"license": "CC0", "license": "CC0",

View File

@ -1,7 +1,7 @@
{ {
"fileVersion": 1, "fileVersion": 1,
"versions": { "versions": {
"handy-http-primitives": "1.0.0", "handy-http-primitives": "1.2.0",
"photon": "0.10.2", "photon": "0.10.2",
"sharded-map": "2.7.0", "sharded-map": "2.7.0",
"streams": "3.5.0" "streams": "3.5.0"

View File

@ -201,15 +201,15 @@ Either!(string[][string], "headers", StreamError, "error") parseHeaders(S)(S inp
return Either!(string[][string], "headers", StreamError, "error")(headers); return Either!(string[][string], "headers", StreamError, "error")(headers);
} }
unittest { // unittest {
class TestHandler : HttpRequestHandler { // class TestHandler : HttpRequestHandler {
void handle(ref ServerHttpRequest request, ref ServerHttpResponse response) { // void handle(ref ServerHttpRequest request, ref ServerHttpResponse response) {
response.status = HttpStatus.OK; // response.status = HttpStatus.OK;
response.headers.add("Content-Type", "application/json"); // response.headers.add("Content-Type", "application/json");
response.outputStream.writeToStream(cast(ubyte[]) "{\"a\": 1}"); // response.outputStream.writeToStream(cast(ubyte[]) "{\"a\": 1}");
} // }
} // }
HttpTransport tp = new Http1Transport(new TestHandler(), 8080); // HttpTransport tp = new Http1Transport(new TestHandler(), 8080);
tp.start(); // tp.start();
} // }

View File

@ -50,28 +50,53 @@ struct HttpResponseOutputStream(S) if (isByteOutputStream!S) {
* Returns: The stream result of writing. * Returns: The stream result of writing.
*/ */
StreamResult writeHeaders() { StreamResult writeHeaders() {
// TODO: Come up with a better way of writing headers than string concatenation.
size_t idx = 0; size_t idx = 0;
char[6] statusCodeBuffer; // Normal HTTP codes are 3 digits, but this leaves room for extensions. char[6] statusCodeBuffer; // Normal HTTP codes are 3 digits, but this leaves room for extensions.
writeUIntToBuffer(response.status.code, statusCodeBuffer, idx); writeUIntToBuffer(response.status.code, statusCodeBuffer, idx);
// Write the status line.
string statusAndHeaders = "HTTP/1.1 " StreamResult r = outputStream.writeToStream(cast(ubyte[]) "HTTP/1.1 ");
~ cast(string) statusCodeBuffer[0..idx] if (r.hasError) return r;
~ " " ~ response.status.text size_t writeCount = r.count;
~ "\r\n"; r = outputStream.writeToStream(cast(ubyte[]) statusCodeBuffer[0..idx]);
if (r.hasError) return r;
writeCount += r.count;
r = outputStream.writeToStream([' ']);
if (r.hasError) return r;
writeCount += r.count;
r = outputStream.writeToStream(cast(ubyte[]) response.status.text);
if (r.hasError) return r;
writeCount += r.count;
r = outputStream.writeToStream(['\r', '\n']);
if (r.hasError) return r;
writeCount += r.count;
foreach (headerName; response.headers.keys) { foreach (headerName; response.headers.keys) {
string headerLine = headerName ~ ": "; // Write the header name.
r = outputStream.writeToStream(cast(ubyte[]) headerName);
if (r.hasError) return r;
writeCount += r.count;
r = outputStream.writeToStream([':', ' ']);
if (r.hasError) return r;
writeCount += r.count;
// Write the comma-separated list of values.
string[] headerValues = response.headers.getAll(headerName); string[] headerValues = response.headers.getAll(headerName);
for (size_t i = 0; i < headerValues.length; i++) { for (size_t i = 0; i < headerValues.length; i++) {
headerLine ~= headerValues[i]; r = outputStream.writeToStream(cast(ubyte[]) headerValues[i]);
if (r.hasError) return r;
writeCount += r.count;
if (i + 1 < headerValues.length) { if (i + 1 < headerValues.length) {
headerLine ~= ", "; r = outputStream.writeToStream([',', ' ']);
if (r.hasError) return r;
writeCount += r.count;
} }
} }
headerLine ~= "\r\n"; r = outputStream.writeToStream(['\r', '\n']);
statusAndHeaders ~= headerLine; if (r.hasError) return r;
writeCount += r.count;
} }
statusAndHeaders ~= "\r\n"; // Trailing CLRF before the body. r = outputStream.writeToStream(['\r', '\n']); // Trailing CLRF before the body.
return outputStream.writeToStream(cast(ubyte[]) statusAndHeaders); if (r.hasError) return r;
writeCount += r.count;
return StreamResult(cast(uint) writeCount);
} }
} }