Zebediah Figura : httpapi: Implement HttpSendHttpResponse().

Alexandre Julliard julliard at winehq.org
Thu Aug 29 15:05:50 CDT 2019


Module: wine
Branch: master
Commit: d73fc3e82af5279f7631cff134c764ba47fb1a08
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=d73fc3e82af5279f7631cff134c764ba47fb1a08

Author: Zebediah Figura <z.figura12 at gmail.com>
Date:   Wed Aug 28 20:45:28 2019 -0500

httpapi: Implement HttpSendHttpResponse().

While it's a little architecturally weird to have this part uniquely
implemented in httpapi, it's far easier to handle building the response
string here than having to marshal everything into an ioctl buffer first.

Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/httpapi/httpapi_main.c | 145 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 141 insertions(+), 4 deletions(-)

diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c
index 08fbe4d..8a970a0 100644
--- a/dlls/httpapi/httpapi_main.c
+++ b/dlls/httpapi/httpapi_main.c
@@ -289,6 +289,18 @@ ULONG WINAPI HttpReceiveHttpRequest(HANDLE queue, HTTP_REQUEST_ID id, ULONG flag
     return ret;
 }
 
+static void format_date(char *buffer)
+{
+    static const char day_names[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+    static const char month_names[12][4] =
+            {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+    SYSTEMTIME date;
+    GetSystemTime(&date);
+    sprintf(buffer + strlen(buffer), "Date: %s, %02u %s %u %02u:%02u:%02u GMT\r\n",
+            day_names[date.wDayOfWeek], date.wDay, month_names[date.wMonth - 1],
+            date.wYear, date.wHour, date.wMinute, date.wSecond);
+}
+
 /***********************************************************************
  *        HttpSendHttpResponse     (HTTPAPI.@)
  */
@@ -296,10 +308,135 @@ ULONG WINAPI HttpSendHttpResponse(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags,
         HTTP_RESPONSE *response, HTTP_CACHE_POLICY *cache_policy, ULONG *ret_size,
         void *reserved1, ULONG reserved2, OVERLAPPED *ovl, HTTP_LOG_DATA *log_data)
 {
-    FIXME("queue %p, id %s, flags %#x, response %p, cache_policy %p, "
-            "ret_size %p, reserved1 %p, reserved2 %#x, ovl %p, log_data %p, stub!\n",
-          queue, wine_dbgstr_longlong(id), flags, response, cache_policy, ret_size, reserved1, reserved2, ovl, log_data);
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    static const char *const header_names[] =
+    {
+        "Cache-Control",
+        "Connection",
+        "Date",
+        "Keep-Alive",
+        "Pragma",
+        "Trailer",
+        "Transfer-Encoding",
+        "Upgrade",
+        "Via",
+        "Warning",
+        "Allow",
+        "Content-Length",
+        "Content-Type",
+        "Content-Encoding",
+        "Content-Language",
+        "Content-Location",
+        "Content-MD5",
+        "Content-Range",
+        "Expires",
+        "Last-Modified",
+        "Accept-Ranges",
+        "Age",
+        "ETag",
+        "Location",
+        "Proxy-Authenticate",
+        "Retry-After",
+        "Server",
+        "Set-Cookie",
+        "Vary",
+        "WWW-Authenticate",
+    };
+
+    struct http_response *buffer;
+    OVERLAPPED dummy_ovl = {};
+    ULONG ret = ERROR_SUCCESS;
+    int len, body_len = 0;
+    char *p, dummy[12];
+    USHORT i;
+
+    TRACE("queue %p, id %s, flags %#x, response %p, cache_policy %p, "
+            "ret_size %p, reserved1 %p, reserved2 %#x, ovl %p, log_data %p.\n",
+            queue, wine_dbgstr_longlong(id), flags, response, cache_policy,
+            ret_size, reserved1, reserved2, ovl, log_data);
+
+    if (flags)
+        FIXME("Unhandled flags %#x.\n", flags);
+    if (response->s.Flags)
+        FIXME("Unhandled response flags %#x.\n", response->s.Flags);
+    if (cache_policy)
+        WARN("Ignoring cache_policy.\n");
+    if (log_data)
+        WARN("Ignoring log_data.\n");
+
+    len = 12 + sprintf(dummy, "%hu", response->s.StatusCode) + response->s.ReasonLength;
+    for (i = 0; i < response->s.EntityChunkCount; ++i)
+    {
+        if (response->s.pEntityChunks[i].DataChunkType != HttpDataChunkFromMemory)
+        {
+            FIXME("Unhandled data chunk type %u.\n", response->s.pEntityChunks[i].DataChunkType);
+            return ERROR_CALL_NOT_IMPLEMENTED;
+        }
+        body_len += response->s.pEntityChunks[i].FromMemory.BufferLength;
+    }
+    len += body_len;
+    for (i = 0; i < HttpHeaderResponseMaximum; ++i)
+    {
+        if (i == HttpHeaderDate)
+            len += 37;
+        else if (response->s.Headers.KnownHeaders[i].RawValueLength)
+            len += strlen(header_names[i]) + 2 + response->s.Headers.KnownHeaders[i].RawValueLength + 2;
+        else if (i == HttpHeaderContentLength)
+        {
+            char dummy[12];
+            len += strlen(header_names[i]) + 2 + sprintf(dummy, "%d", body_len) + 2;
+        }
+    }
+    for (i = 0; i < response->s.Headers.UnknownHeaderCount; ++i)
+    {
+        len += response->s.Headers.pUnknownHeaders[i].NameLength + 2;
+        len += response->s.Headers.pUnknownHeaders[i].RawValueLength + 2;
+    }
+    len += 2;
+
+    if (!(buffer = heap_alloc(offsetof(struct http_response, buffer[len]))))
+        return ERROR_OUTOFMEMORY;
+    buffer->id = id;
+    buffer->len = len;
+    sprintf(buffer->buffer, "HTTP/1.1 %u %.*s\r\n", response->s.StatusCode,
+            response->s.ReasonLength, response->s.pReason);
+
+    for (i = 0; i < HttpHeaderResponseMaximum; ++i)
+    {
+        const HTTP_KNOWN_HEADER *header = &response->s.Headers.KnownHeaders[i];
+        if (i == HttpHeaderDate)
+            format_date(buffer->buffer);
+        else if (header->RawValueLength)
+            sprintf(buffer->buffer + strlen(buffer->buffer), "%s: %.*s\r\n",
+                    header_names[i], header->RawValueLength, header->pRawValue);
+        else if (i == HttpHeaderContentLength)
+            sprintf(buffer->buffer + strlen(buffer->buffer), "Content-Length: %d\r\n", body_len);
+    }
+    for (i = 0; i < response->s.Headers.UnknownHeaderCount; ++i)
+    {
+        const HTTP_UNKNOWN_HEADER *header = &response->s.Headers.pUnknownHeaders[i];
+        sprintf(buffer->buffer + strlen(buffer->buffer), "%.*s: %.*s\r\n", header->NameLength,
+                header->pName, header->RawValueLength, header->pRawValue);
+    }
+    p = buffer->buffer + strlen(buffer->buffer);
+    /* Don't use strcat, because this might be the end of the buffer. */
+    memcpy(p, "\r\n", 2);
+    p += 2;
+    for (i = 0; i < response->s.EntityChunkCount; ++i)
+    {
+        const HTTP_DATA_CHUNK *chunk = &response->s.pEntityChunks[i];
+        memcpy(p, chunk->FromMemory.pBuffer, chunk->FromMemory.BufferLength);
+        p += chunk->FromMemory.BufferLength;
+    }
+
+    if (!ovl)
+        ovl = &dummy_ovl;
+
+    if (!DeviceIoControl(queue, IOCTL_HTTP_SEND_RESPONSE, buffer,
+            offsetof(struct http_response, buffer[len]), NULL, 0, NULL, ovl))
+        ret = GetLastError();
+
+    heap_free(buffer);
+    return ret;
 }
 
 /***********************************************************************




More information about the wine-cvs mailing list