diff --git a/doc/xml/release.xml b/doc/xml/release.xml index 740076200..906e3e14b 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -111,6 +111,14 @@

Add support for HTTP/1.0.

+ + + + + + +

Add user-agent to HTTP requests.

+
diff --git a/src/common/io/http/request.c b/src/common/io/http/request.c index fb484ed77..d957b8209 100644 --- a/src/common/io/http/request.c +++ b/src/common/io/http/request.c @@ -9,6 +9,7 @@ HTTP Request #include "common/log.h" #include "common/type/object.h" #include "common/wait.h" +#include "version.h" /*********************************************************************************************************************************** HTTP constants @@ -29,6 +30,7 @@ STRING_EXTERN(HTTP_HEADER_ETAG_STR, HTTP_HEADER_ STRING_EXTERN(HTTP_HEADER_DATE_STR, HTTP_HEADER_DATE); STRING_EXTERN(HTTP_HEADER_HOST_STR, HTTP_HEADER_HOST); STRING_EXTERN(HTTP_HEADER_LAST_MODIFIED_STR, HTTP_HEADER_LAST_MODIFIED); +#define HTTP_HEADER_USER_AGENT "user-agent" // 5xx errors that should always be retried #define HTTP_RESPONSE_CODE_RETRY_CLASS 5 @@ -101,11 +103,12 @@ httpRequestProcess(HttpRequest *this, bool waitForResponse, bool contentCache) { session = httpClientOpen(this->client); - // Format the request + // Format the request and user agent String *requestStr = strNewFmt( - "%s %s%s%s " HTTP_VERSION CRLF_Z, strZ(this->verb), strZ(httpUriEncode(this->uri, true)), - this->query == NULL ? "" : "?", this->query == NULL ? "" : strZ(httpQueryRenderP(this->query))); + "%s %s%s%s " HTTP_VERSION CRLF_Z HTTP_HEADER_USER_AGENT ":" PROJECT_NAME "/" PROJECT_VERSION CRLF_Z, + strZ(this->verb), strZ(httpUriEncode(this->uri, true)), this->query == NULL ? "" : "?", + this->query == NULL ? "" : strZ(httpQueryRenderP(this->query))); // Add headers const StringList *headerList = httpHeaderList(this->header); diff --git a/test/src/module/common/ioHttpTest.c b/test/src/module/common/ioHttpTest.c index 70a1f6772..b79218666 100644 --- a/test/src/module/common/ioHttpTest.c +++ b/test/src/module/common/ioHttpTest.c @@ -11,6 +11,12 @@ Test HTTP #include "common/harnessFork.h" #include "common/harnessServer.h" +/*********************************************************************************************************************************** +HTTP user agent header +***********************************************************************************************************************************/ +#define TEST_USER_AGENT \ + HTTP_HEADER_USER_AGENT ":" PROJECT_NAME "/" PROJECT_VERSION "\r\n" + /*********************************************************************************************************************************** Test Run ***********************************************************************************************************************************/ @@ -214,7 +220,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptSleep(http, 600); hrnServerScriptClose(http); @@ -228,7 +234,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.0 200 OK\n"); hrnServerScriptClose(http); @@ -242,7 +248,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.0 200\r\n"); hrnServerScriptClose(http); @@ -256,7 +262,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1 200 OK\r\n"); hrnServerScriptClose(http); @@ -270,7 +276,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200OK\r\n"); hrnServerScriptClose(http); @@ -284,7 +290,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\n"); hrnServerScriptClose(http); @@ -298,7 +304,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\nheader-value\r\n"); hrnServerScriptClose(http); @@ -312,7 +318,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\ntransfer-encoding:bogus\r\n"); hrnServerScriptClose(http); @@ -326,7 +332,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\ntransfer-encoding:chunked\r\ncontent-length:777\r\n\r\n"); hrnServerScriptClose(http); @@ -340,7 +346,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 503 Slow Down\r\n\r\n"); hrnServerScriptClose(http); @@ -354,13 +360,15 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET /?name=%2Fpath%2FA%20Z.txt&type=test HTTP/1.1\r\nhost:myhost.com\r\n\r\n"); + hrnServerScriptExpectZ(http, + "GET /?name=%2Fpath%2FA%20Z.txt&type=test HTTP/1.1\r\n" TEST_USER_AGENT "host:myhost.com\r\n\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 500 Internal Error\r\nConnection:close\r\n\r\n"); hrnServerScriptClose(http); hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET /?name=%2Fpath%2FA%20Z.txt&type=test HTTP/1.1\r\nhost:myhost.com\r\n\r\n"); + hrnServerScriptExpectZ( + http, "GET /?name=%2Fpath%2FA%20Z.txt&type=test HTTP/1.1\r\n" TEST_USER_AGENT "host:myhost.com\r\n\r\n"); hrnServerScriptReplyZ( http, "HTTP/1.1 200 OK\r\nkey1:0\r\n key2 : value2\r\nConnection:ack\r\ncontent-length:0\r\n\r\n"); @@ -409,7 +417,7 @@ testRun(void) // ----------------------------------------------------------------------------------------------------------------- TEST_TITLE("head request with content-length but no content"); - hrnServerScriptExpectZ(http, "HEAD / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "HEAD / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.0 200 OK\r\ncontent-length:380\r\n\r\n"); hrnServerScriptClose(http); @@ -427,7 +435,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "HEAD / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "HEAD / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); TEST_ASSIGN(response, httpRequestResponse(httpRequestNewP(client, strNew("HEAD"), strNew("/")), true), "request"); @@ -441,7 +449,7 @@ testRun(void) // ----------------------------------------------------------------------------------------------------------------- TEST_TITLE("head request with connection close but no content"); - hrnServerScriptExpectZ(http, "HEAD / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "HEAD / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\nConnection:close\r\n\r\n"); hrnServerScriptClose(http); @@ -459,20 +467,20 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 503 Slow Down\r\ncontent-length:3\r\nConnection:close\r\n\r\n123"); hrnServerScriptClose(http); hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ( http, "HTTP/1.1 503 Slow Down\r\nTransfer-Encoding:chunked\r\nConnection:close\r\n\r\n0\r\n\r\n"); hrnServerScriptClose(http); hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 404 Not Found\r\n\r\n"); TEST_ASSIGN(request, httpRequestNewP(client, strNew("GET"), strNew("/")), "request"); @@ -492,7 +500,7 @@ testRun(void) // ----------------------------------------------------------------------------------------------------------------- TEST_TITLE("error with content"); - hrnServerScriptExpectZ(http, "GET /?a=b HTTP/1.1\r\nhdr1:1\r\nhdr2:2\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET /?a=b HTTP/1.1\r\n" TEST_USER_AGENT "hdr1:1\r\nhdr2:2\r\n\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 403 \r\ncontent-length:7\r\n\r\nCONTENT"); StringList *headerRedact = strLstNew(); @@ -531,7 +539,8 @@ testRun(void) TEST_TITLE("request with content using content-length"); hrnServerScriptExpectZ( - http, "GET /path/file%201.txt HTTP/1.1\r\ncontent-length:30\r\n\r\n012345678901234567890123456789"); + http, "GET /path/file%201.txt HTTP/1.1\r\n" TEST_USER_AGENT "content-length:30\r\n\r\n" + "012345678901234567890123456789"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\nConnection:close\r\n\r\n01234567890123456789012345678901"); hrnServerScriptClose(http); @@ -556,13 +565,13 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET /path/file%201.txt HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET /path/file%201.txt HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\ncontent-length:32\r\n\r\n0123456789012345678901234567890"); hrnServerScriptClose(http); hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET /path/file%201.txt HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET /path/file%201.txt HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\ncontent-length:32\r\n\r\n01234567890123456789012345678901"); TEST_ASSIGN( @@ -574,7 +583,7 @@ testRun(void) // ----------------------------------------------------------------------------------------------------------------- TEST_TITLE("request with eof before content complete"); - hrnServerScriptExpectZ(http, "GET /path/file%201.txt HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET /path/file%201.txt HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ(http, "HTTP/1.1 200 OK\r\ncontent-length:32\r\n\r\n0123456789012345678901234567890"); hrnServerScriptClose(http); @@ -591,7 +600,7 @@ testRun(void) hrnServerScriptAccept(http); - hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n\r\n"); + hrnServerScriptExpectZ(http, "GET / HTTP/1.1\r\n" TEST_USER_AGENT "\r\n"); hrnServerScriptReplyZ( http, "HTTP/1.1 200 OK\r\nTransfer-Encoding:chunked\r\n\r\n" diff --git a/test/src/module/storage/azureTest.c b/test/src/module/storage/azureTest.c index 50e1bf105..13089648c 100644 --- a/test/src/module/storage/azureTest.c +++ b/test/src/module/storage/azureTest.c @@ -60,8 +60,8 @@ testRequest(IoWrite *write, const char *verb, const char *uri, TestRequestParam else strCatZ(request, uri); - // Add HTTP version - strCatZ(request, " HTTP/1.1\r\n"); + // Add HTTP version and user agent + strCatZ(request, " HTTP/1.1\r\nuser-agent:" PROJECT_NAME "/" PROJECT_VERSION "\r\n"); // Add authorization string if (driver->sharedKey != NULL) diff --git a/test/src/module/storage/s3Test.c b/test/src/module/storage/s3Test.c index 588e13c6f..431e2f029 100644 --- a/test/src/module/storage/s3Test.c +++ b/test/src/module/storage/s3Test.c @@ -5,6 +5,7 @@ Test S3 Storage #include "common/io/fdRead.h" #include "common/io/fdWrite.h" +#include "version.h" #include "common/harnessConfig.h" #include "common/harnessFork.h" @@ -36,9 +37,10 @@ testRequest(IoWrite *write, Storage *s3, const char *verb, const char *uri, Test // Get S3 driver StorageS3 *driver = (StorageS3 *)storageDriver(s3); - // Add authorization string + // Add verb, uri, version, user-agent, and authorization string String *request = strNewFmt( "%s %s HTTP/1.1\r\n" + "user-agent:" PROJECT_NAME "/" PROJECT_VERSION "\r\n" "authorization:AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/\?\?\?\?\?\?\?\?/us-east-1/s3/aws4_request," "SignedHeaders=content-length", verb, uri);