diff options
| author | Stefan Boberg <[email protected]> | 2021-09-28 23:24:45 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-09-28 23:24:45 +0200 |
| commit | 46eebda16a2c3a66bb8ca48488e49d659556d745 (patch) | |
| tree | c5fb2662c2cf5e3fb4efc2e263e8663d37723747 | |
| parent | Removed IsPointerToStack() (diff) | |
| download | zen-46eebda16a2c3a66bb8ca48488e49d659556d745.tar.xz zen-46eebda16a2c3a66bb8ca48488e49d659556d745.zip | |
http: ReasonStringForHttpResultCode returns string_view to avoid strlen
| -rw-r--r-- | zenhttp/httpserver.cpp | 118 | ||||
| -rw-r--r-- | zenhttp/httpsys.cpp | 105 | ||||
| -rw-r--r-- | zenhttp/include/zenhttp/httpcommon.h | 2 |
3 files changed, 111 insertions, 114 deletions
diff --git a/zenhttp/httpserver.cpp b/zenhttp/httpserver.cpp index 795e81ea8..78fc34984 100644 --- a/zenhttp/httpserver.cpp +++ b/zenhttp/httpserver.cpp @@ -152,7 +152,7 @@ ToString(HttpVerb Verb) } } -const char* +std::string_view ReasonStringForHttpResultCode(int HttpCode) { switch (HttpCode) @@ -160,132 +160,132 @@ ReasonStringForHttpResultCode(int HttpCode) // 1xx Informational case 100: - return "Continue"; + return "Continue"sv; case 101: - return "Switching Protocols"; + return "Switching Protocols"sv; // 2xx Success case 200: - return "OK"; + return "OK"sv; case 201: - return "Created"; + return "Created"sv; case 202: - return "Accepted"; + return "Accepted"sv; case 204: - return "No Content"; + return "No Content"sv; case 205: - return "Reset Content"; + return "Reset Content"sv; case 206: - return "Partial Content"; + return "Partial Content"sv; // 3xx Redirection case 300: - return "Multiple Choices"; + return "Multiple Choices"sv; case 301: - return "Moved Permanently"; + return "Moved Permanently"sv; case 302: - return "Found"; + return "Found"sv; case 303: - return "See Other"; + return "See Other"sv; case 304: - return "Not Modified"; + return "Not Modified"sv; case 305: - return "Use Proxy"; + return "Use Proxy"sv; case 306: - return "Switch Proxy"; + return "Switch Proxy"sv; case 307: - return "Temporary Redirect"; + return "Temporary Redirect"sv; case 308: - return "Permanent Redirect"; + return "Permanent Redirect"sv; // 4xx Client errors case 400: - return "Bad Request"; + return "Bad Request"sv; case 401: - return "Unauthorized"; + return "Unauthorized"sv; case 402: - return "Payment Required"; + return "Payment Required"sv; case 403: - return "Forbidden"; + return "Forbidden"sv; case 404: - return "Not Found"; + return "Not Found"sv; case 405: - return "Method Not Allowed"; + return "Method Not Allowed"sv; case 406: - return "Not Acceptable"; + return "Not Acceptable"sv; case 407: - return "Proxy Authentication Required"; + return "Proxy Authentication Required"sv; case 408: - return "Request Timeout"; + return "Request Timeout"sv; case 409: - return "Conflict"; + return "Conflict"sv; case 410: - return "Gone"; + return "Gone"sv; case 411: - return "Length Required"; + return "Length Required"sv; case 412: - return "Precondition Failed"; + return "Precondition Failed"sv; case 413: - return "Payload Too Large"; + return "Payload Too Large"sv; case 414: - return "URI Too Long"; + return "URI Too Long"sv; case 415: - return "Unsupported Media Type"; + return "Unsupported Media Type"sv; case 416: - return "Range Not Satisifiable"; + return "Range Not Satisifiable"sv; case 417: - return "Expectation Failed"; + return "Expectation Failed"sv; case 418: - return "I'm a teapot"; + return "I'm a teapot"sv; case 421: - return "Misdirected Request"; + return "Misdirected Request"sv; case 422: - return "Unprocessable Entity"; + return "Unprocessable Entity"sv; case 423: - return "Locked"; + return "Locked"sv; case 424: - return "Failed Dependency"; + return "Failed Dependency"sv; case 425: - return "Too Early"; + return "Too Early"sv; case 426: - return "Upgrade Required"; + return "Upgrade Required"sv; case 428: - return "Precondition Required"; + return "Precondition Required"sv; case 429: - return "Too Many Requests"; + return "Too Many Requests"sv; case 431: - return "Request Header Fields Too Large"; + return "Request Header Fields Too Large"sv; // 5xx Server errors case 500: - return "Internal Server Error"; + return "Internal Server Error"sv; case 501: - return "Not Implemented"; + return "Not Implemented"sv; case 502: - return "Bad Gateway"; + return "Bad Gateway"sv; case 503: - return "Service Unavailable"; + return "Service Unavailable"sv; case 504: - return "Gateway Timeout"; + return "Gateway Timeout"sv; case 505: - return "HTTP Version Not Supported"; + return "HTTP Version Not Supported"sv; case 506: - return "Variant Also Negotiates"; + return "Variant Also Negotiates"sv; case 507: - return "Insufficient Storage"; + return "Insufficient Storage"sv; case 508: - return "Loop Detected"; + return "Loop Detected"sv; case 510: - return "Not Extended"; + return "Not Extended"sv; case 511: - return "Network Authentication Required"; + return "Network Authentication Required"sv; default: - return "Unknown Result"; + return "Unknown Result"sv; } } @@ -545,7 +545,7 @@ HttpRequestRouter::HandleRequest(zen::HttpServerRequest& Request) Ref<HttpServer> CreateHttpServer() { -#if 0 +#if 1 return new HttpUwsServer; #elif ZEN_WITH_HTTPSYS return new HttpSysServer{std::thread::hardware_concurrency()}; diff --git a/zenhttp/httpsys.cpp b/zenhttp/httpsys.cpp index bccff24ab..9b2e7f832 100644 --- a/zenhttp/httpsys.cpp +++ b/zenhttp/httpsys.cpp @@ -18,47 +18,43 @@ # pragma comment(lib, "httpapi.lib") std::wstring -UTF8_to_wstring(const char* in) +UTF8_to_UTF16(const char* InPtr) { - std::wstring out; - unsigned int codepoint; + std::wstring OutString; + unsigned int Codepoint; - while (*in != 0) + while (*InPtr != 0) { - unsigned char ch = static_cast<unsigned char>(*in); - - if (ch <= 0x7f) - codepoint = ch; - else if (ch <= 0xbf) - codepoint = (codepoint << 6) | (ch & 0x3f); - else if (ch <= 0xdf) - codepoint = ch & 0x1f; - else if (ch <= 0xef) - codepoint = ch & 0x0f; + unsigned char InChar = static_cast<unsigned char>(*InPtr); + + if (InChar <= 0x7f) + Codepoint = InChar; + else if (InChar <= 0xbf) + Codepoint = (Codepoint << 6) | (InChar & 0x3f); + else if (InChar <= 0xdf) + Codepoint = InChar & 0x1f; + else if (InChar <= 0xef) + Codepoint = InChar & 0x0f; else - codepoint = ch & 0x07; + Codepoint = InChar & 0x07; - ++in; + ++InPtr; - if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff)) + if (((*InPtr & 0xc0) != 0x80) && (Codepoint <= 0x10ffff)) { - if constexpr (sizeof(wchar_t) > 2) + if (Codepoint > 0xffff) { - out.append(1, static_cast<wchar_t>(codepoint)); + OutString.append(1, static_cast<wchar_t>(0xd800 + (Codepoint >> 10))); + OutString.append(1, static_cast<wchar_t>(0xdc00 + (Codepoint & 0x03ff))); } - else if (codepoint > 0xffff) + else if (Codepoint < 0xd800 || Codepoint >= 0xe000) { - out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10))); - out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff))); - } - else if (codepoint < 0xd800 || codepoint >= 0xe000) - { - out.append(1, static_cast<wchar_t>(codepoint)); + OutString.append(1, static_cast<wchar_t>(Codepoint)); } } } - return out; + return OutString; } namespace zen { @@ -493,6 +489,7 @@ HttpMessageResponseRequest::IssueRequest(std::error_code& ErrorCode) // Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters // // Set DisableServerHeader to 1 to disable suffix, or 2 to disable the header altogether + // (only the latter appears to do anything in my testing, on Windows 10). // // (reference https://docs.microsoft.com/en-us/archive/blogs/dsnotes/wswcf-remove-server-header) // @@ -519,9 +516,11 @@ HttpMessageResponseRequest::IssueRequest(std::error_code& ErrorCode) ContentTypeHeader->pRawValue = ContentTypeString.data(); ContentTypeHeader->RawValueLength = (USHORT)ContentTypeString.size(); + std::string_view ReasonString = ReasonStringForHttpResultCode(m_ResponseCode); + HttpResponse.StatusCode = m_ResponseCode; - HttpResponse.pReason = ReasonStringForHttpResultCode(m_ResponseCode); - HttpResponse.ReasonLength = (USHORT)strlen(HttpResponse.pReason); + HttpResponse.pReason = ReasonString.data(); + HttpResponse.ReasonLength = (USHORT)ReasonString.size(); // Cache policy @@ -823,18 +822,18 @@ HttpSysServer::RegisterService(const char* UrlPath, HttpService& Service) ++UrlPath; } - const std::wstring Path16 = UTF8_to_wstring(UrlPath); - Service.SetUriPrefixLength(Path16.size() + 1 /* leading slash */); + const std::wstring PathUtf16 = UTF8_to_UTF16(UrlPath); + Service.SetUriPrefixLength(PathUtf16.size() + 1 /* leading slash */); // Convert to wide string - std::wstring Url16 = m_BaseUri + Path16; + std::wstring Url16 = m_BaseUri + PathUtf16; ULONG Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, Url16.c_str(), HTTP_URL_CONTEXT(&Service), 0 /* Reserved */); if (Result != NO_ERROR) { - ZEN_ERROR("HttpAddUrlToUrlGroup failed with result {}", Result); + ZEN_ERROR("HttpAddUrlToUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result)); return; } @@ -850,17 +849,17 @@ HttpSysServer::UnregisterService(const char* UrlPath, HttpService& Service) ++UrlPath; } - const std::wstring Path16 = UTF8_to_wstring(UrlPath); + const std::wstring PathUtf16 = UTF8_to_UTF16(UrlPath); // Convert to wide string - std::wstring Url16 = m_BaseUri + Path16; + std::wstring Url16 = m_BaseUri + PathUtf16; ULONG Result = HttpRemoveUrlFromUrlGroup(m_HttpUrlGroupId, Url16.c_str(), 0); if (Result != NO_ERROR) { - ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result {}", Result); + ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result)); } } @@ -1269,7 +1268,7 @@ InitialRequestHandler::IssueRequest(std::error_code& ErrorCode) ErrorCode = MakeErrorCode(HttpApiResult); - ZEN_ERROR("HttpReceiveHttpRequest failed, error {}", ErrorCode.message()); + ZEN_ERROR("HttpReceiveHttpRequest failed, error: '{}'", ErrorCode.message()); return; } @@ -1293,7 +1292,7 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT break; } - // Route requests + // Route request try { @@ -1400,28 +1399,26 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT m_CurrentPayloadOffset += NumberOfBytesTransferred; } - if (m_CurrentPayloadOffset == m_ContentLength) + if (m_CurrentPayloadOffset != m_ContentLength) { - m_PayloadBuffer.MakeImmutable(); + // Body not complete, issue another read request to receive more body data + return this; + } - // Body received completely - call request handler + // Request body received completely - HttpSysServerRequest& ThisRequest = Transaction().InvokeRequestHandler(*Service, m_PayloadBuffer); + m_PayloadBuffer.MakeImmutable(); - if (!ThisRequest.IsHandled()) - { - return new HttpMessageResponseRequest(Transaction(), 404, "Not found"sv); - } + HttpSysServerRequest& ThisRequest = Transaction().InvokeRequestHandler(*Service, m_PayloadBuffer); - if (HttpMessageResponseRequest* Response = ThisRequest.m_Response) - { - return Response; - } + if (!ThisRequest.IsHandled()) + { + return new HttpMessageResponseRequest(Transaction(), 404, "Not found"sv); } - else + + if (HttpMessageResponseRequest* Response = ThisRequest.m_Response) { - // Issue a read request for more body data - return this; + return Response; } } @@ -1430,7 +1427,7 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT } catch (std::exception& ex) { - // TODO provide more meaningful error output + ZEN_ERROR("Caught exception while handling request: '{}'", ex.what()); return new HttpMessageResponseRequest(Transaction(), 500, ex.what()); } diff --git a/zenhttp/include/zenhttp/httpcommon.h b/zenhttp/include/zenhttp/httpcommon.h index 62070061c..3e213ece4 100644 --- a/zenhttp/include/zenhttp/httpcommon.h +++ b/zenhttp/include/zenhttp/httpcommon.h @@ -19,7 +19,7 @@ class StringBuilderBase; std::string_view MapContentTypeToString(HttpContentType ContentType); extern HttpContentType (*ParseContentType)(const std::string_view& ContentTypeString); -const char* ReasonStringForHttpResultCode(int HttpCode); +std::string_view ReasonStringForHttpResultCode(int HttpCode); [[nodiscard]] inline bool IsHttpSuccessCode(int HttpCode) |