widl: Generate helper macros for WinRT implementation.
[wine/zf.git] / dlls / http.sys / request.h
bloba1b77b67dc55537ed3d44616e8cc6dc943a4983a
1 /*
2 * Copyright 2019 Zebediah Figura
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 /* We have to return the HTTP_REQUEST structure to userspace exactly as it will
20 * be consumed; httpapi has no opportunity to massage it. Since it contains
21 * pointers, this is somewhat nontrivial. */
23 struct http_unknown_header
25 USHORT NameLength;
26 USHORT RawValueLength;
27 POINTER pName; /* char string */
28 POINTER pRawValue; /* char string */
31 struct http_data_chunk
33 HTTP_DATA_CHUNK_TYPE DataChunkType;
34 union
36 struct
38 POINTER pBuffer; /* char string */
39 ULONG BufferLength;
40 } FromMemory;
41 /* for the struct size */
42 struct
44 ULARGE_INTEGER StartingOffset;
45 ULARGE_INTEGER Length;
46 POINTER FileHandle;
47 } FromFileHandle;
51 struct http_request
53 ULONG Flags;
54 HTTP_CONNECTION_ID ConnectionId;
55 HTTP_REQUEST_ID RequestId;
56 HTTP_URL_CONTEXT UrlContext;
57 HTTP_VERSION Version;
58 HTTP_VERB Verb;
59 USHORT UnknownVerbLength;
60 USHORT RawUrlLength;
61 POINTER pUnknownVerb; /* char string */
62 POINTER pRawUrl; /* char string */
63 struct
65 USHORT FullUrlLength;
66 USHORT HostLength;
67 USHORT AbsPathLength;
68 USHORT QueryStringLength;
69 POINTER pFullUrl; /* WCHAR string */
70 POINTER pHost; /* pointer to above */
71 POINTER pAbsPath; /* pointer to above */
72 POINTER pQueryString; /* pointer to above */
73 } CookedUrl;
74 struct
76 POINTER pRemoteAddress; /* SOCKADDR */
77 POINTER pLocalAddress; /* SOCKADDR */
78 } Address;
79 struct
81 USHORT UnknownHeaderCount;
82 POINTER pUnknownHeaders; /* struct http_unknown_header */
83 USHORT TrailerCount;
84 POINTER pTrailers; /* NULL */
85 struct
87 USHORT RawValueLength;
88 POINTER pRawValue; /* char string */
89 } KnownHeaders[HttpHeaderRequestMaximum];
90 } Headers;
91 ULONGLONG BytesReceived;
92 USHORT EntityChunkCount;
93 POINTER pEntityChunks; /* struct http_data_chunk */
94 HTTP_RAW_CONNECTION_ID RawConnectionId;
95 POINTER pSslInfo; /* NULL (FIXME) */
96 USHORT RequestInfoCount;
97 POINTER pRequestInfo; /* NULL (FIXME) */
100 static NTSTATUS complete_irp(struct connection *conn, IRP *irp)
102 const struct http_receive_request_params params
103 = *(struct http_receive_request_params *)irp->AssociatedIrp.SystemBuffer;
104 ULONG cooked_len, host_len, abs_path_len, query_len, chunk_len = 0, offset, processed;
105 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
106 const DWORD output_len = stack->Parameters.DeviceIoControl.OutputBufferLength;
107 struct http_request *req = irp->AssociatedIrp.SystemBuffer;
108 const char *p, *name, *value, *host, *abs_path, *query;
109 struct http_unknown_header *unk_headers = NULL;
110 char *buffer = irp->AssociatedIrp.SystemBuffer;
111 DWORD irp_size = sizeof(struct http_request);
112 USHORT unk_headers_count = 0, unk_header_idx;
113 struct http_data_chunk *chunk = NULL;
114 int name_len, value_len, len;
115 struct sockaddr_in addr;
117 /* First calculate the total buffer size needed for this IRP. */
119 if (conn->unk_verb_len)
120 irp_size += conn->unk_verb_len + 1;
121 irp_size += conn->url_len + 1;
123 /* cooked URL */
124 if (conn->url[0] == '/')
126 p = host = conn->host;
127 while (isgraph(*p)) ++p;
128 host_len = p - conn->host;
129 abs_path = conn->url;
130 abs_path_len = conn->url_len;
132 else
134 host = conn->url + 7;
135 abs_path = strchr(host, '/');
136 host_len = abs_path - host;
137 abs_path_len = (conn->url + conn->url_len) - abs_path;
139 if ((query = memchr(abs_path, '?', abs_path_len)))
141 query_len = (abs_path + abs_path_len) - query;
142 abs_path_len = query - abs_path;
144 else
145 query_len = 0;
146 cooked_len = (7 /* scheme */ + host_len + abs_path_len + query_len) * sizeof(WCHAR);
147 irp_size += cooked_len + sizeof(WCHAR);
149 /* addresses */
150 irp_size += 2 * sizeof(addr);
152 /* headers */
153 p = strstr(conn->buffer, "\r\n") + 2;
154 while (memcmp(p, "\r\n", 2))
156 name = p;
157 parse_header(name, &name_len, &value, &value_len);
158 if (parse_header_name(name, name_len) == HttpHeaderRequestMaximum)
160 irp_size += name_len + 1;
161 ++unk_headers_count;
163 irp_size += value_len + 1;
164 p = strstr(p, "\r\n") + 2;
166 p += 2;
168 irp_size += unk_headers_count * sizeof(struct http_unknown_header);
170 TRACE("Need %u bytes, have %u.\n", irp_size, output_len);
171 irp->IoStatus.Information = irp_size;
173 memset(irp->AssociatedIrp.SystemBuffer, 0, output_len);
175 if (output_len < irp_size)
177 req->ConnectionId = (ULONG_PTR)conn;
178 req->RequestId = conn->req_id;
179 return STATUS_BUFFER_OVERFLOW;
182 offset = sizeof(*req);
184 req->ConnectionId = (ULONG_PTR)conn;
185 req->RequestId = conn->req_id;
186 req->UrlContext = conn->queue->context;
187 req->Version = conn->version;
188 req->Verb = conn->verb;
189 req->UnknownVerbLength = conn->unk_verb_len;
190 req->RawUrlLength = conn->url_len;
192 if (conn->unk_verb_len)
194 req->pUnknownVerb = params.addr + offset;
195 memcpy(buffer + offset, conn->buffer, conn->unk_verb_len);
196 offset += conn->unk_verb_len;
197 buffer[offset++] = 0;
200 req->pRawUrl = params.addr + offset;
201 memcpy(buffer + offset, conn->url, conn->url_len);
202 offset += conn->url_len;
203 buffer[offset++] = 0;
205 req->CookedUrl.FullUrlLength = cooked_len;
206 req->CookedUrl.HostLength = host_len * sizeof(WCHAR);
207 req->CookedUrl.AbsPathLength = abs_path_len * sizeof(WCHAR);
208 req->CookedUrl.QueryStringLength = query_len * sizeof(WCHAR);
209 req->CookedUrl.pFullUrl = params.addr + offset;
210 req->CookedUrl.pHost = req->CookedUrl.pFullUrl + 7 * sizeof(WCHAR);
211 req->CookedUrl.pAbsPath = req->CookedUrl.pHost + host_len * sizeof(WCHAR);
212 if (query)
213 req->CookedUrl.pQueryString = req->CookedUrl.pAbsPath + abs_path_len * sizeof(WCHAR);
215 memcpy(buffer + offset, L"http://", sizeof(L"http://"));
216 offset += 7 * sizeof(WCHAR);
217 MultiByteToWideChar(CP_ACP, 0, host, host_len, (WCHAR *)(buffer + offset), host_len * sizeof(WCHAR));
218 offset += host_len * sizeof(WCHAR);
219 MultiByteToWideChar(CP_ACP, 0, abs_path, abs_path_len + query_len,
220 (WCHAR *)(buffer + offset), (abs_path_len + query_len) * sizeof(WCHAR));
221 offset += (abs_path_len + query_len) * sizeof(WCHAR);
222 buffer[offset++] = 0;
223 buffer[offset++] = 0;
225 req->Address.pRemoteAddress = params.addr + offset;
226 len = sizeof(addr);
227 getpeername(conn->socket, (struct sockaddr *)&addr, &len);
228 memcpy(buffer + offset, &addr, sizeof(addr));
229 offset += sizeof(addr);
231 req->Address.pLocalAddress = params.addr + offset;
232 len = sizeof(addr);
233 getsockname(conn->socket, (struct sockaddr *)&addr, &len);
234 memcpy(buffer + offset, &addr, sizeof(addr));
235 offset += sizeof(addr);
237 req->Headers.UnknownHeaderCount = unk_headers_count;
238 if (unk_headers_count)
240 req->Headers.pUnknownHeaders = params.addr + offset;
241 unk_headers = (struct http_unknown_header *)(buffer + offset);
242 offset += unk_headers_count * sizeof(*unk_headers);
245 unk_header_idx = 0;
246 p = strstr(conn->buffer, "\r\n") + 2;
247 while (memcmp(p, "\r\n", 2))
249 HTTP_HEADER_ID id;
251 name = p;
252 parse_header(name, &name_len, &value, &value_len);
253 if ((id = parse_header_name(name, name_len)) == HttpHeaderRequestMaximum)
255 unk_headers[unk_header_idx].NameLength = name_len;
256 unk_headers[unk_header_idx].RawValueLength = value_len;
257 unk_headers[unk_header_idx].pName = params.addr + offset;
258 memcpy(buffer + offset, name, name_len);
259 offset += name_len;
260 buffer[offset++] = 0;
261 unk_headers[unk_header_idx].pRawValue = params.addr + offset;
262 memcpy(buffer + offset, value, value_len);
263 offset += value_len;
264 buffer[offset++] = 0;
265 ++unk_header_idx;
267 else
269 req->Headers.KnownHeaders[id].RawValueLength = value_len;
270 req->Headers.KnownHeaders[id].pRawValue = params.addr + offset;
271 memcpy(buffer + offset, value, value_len);
272 offset += value_len;
273 buffer[offset++] = 0;
275 p = strstr(p, "\r\n") + 2;
277 p += 2;
279 if (irp_size + sizeof(*chunk) < output_len && (params.flags & HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY))
280 chunk_len = min(conn->content_len, output_len - (irp_size + sizeof(*chunk)));
281 if (chunk_len)
283 req->EntityChunkCount = 1;
284 req->pEntityChunks = params.addr + offset;
285 chunk = (struct http_data_chunk *)(buffer + offset);
286 offset += sizeof(*chunk);
287 chunk->DataChunkType = HttpDataChunkFromMemory;
288 chunk->FromMemory.BufferLength = chunk_len;
289 chunk->FromMemory.pBuffer = params.addr + offset;
290 memcpy(buffer + offset, p, chunk_len);
291 offset += chunk_len;
293 irp->IoStatus.Information = irp_size + sizeof(*chunk) + chunk_len;
296 if (chunk_len < conn->content_len)
297 req->Flags |= HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS;
299 req->BytesReceived = conn->req_len;
301 assert(offset == irp->IoStatus.Information);
303 conn->available = FALSE;
304 processed = conn->req_len - (conn->content_len - chunk_len);
305 memmove(conn->buffer, conn->buffer + processed, conn->len - processed);
306 conn->content_len -= chunk_len;
307 conn->len -= processed;
309 return STATUS_SUCCESS;