blob: aba39515b971c7bdcc5b79277299bc9813a0a30d [file] [log] [blame]
Vincent Béron9a624912002-05-31 23:06:46 +00001/*
Ulrich Czekallac2757242000-06-11 20:04:44 +00002 * Wininet - Http Implementation
3 *
4 * Copyright 1999 Corel Corporation
5 *
6 * Ulrich Czekalla
7 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00008 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Ulrich Czekallac2757242000-06-11 20:04:44 +000021 */
22
Patrik Stridvall4710be22000-06-23 15:47:14 +000023#include "config.h"
24
Ulrich Czekallac2757242000-06-11 20:04:44 +000025#include <sys/types.h>
Patrik Stridvall4710be22000-06-23 15:47:14 +000026#ifdef HAVE_SYS_SOCKET_H
27# include <sys/socket.h>
28#endif
Ulrich Czekallac2757242000-06-11 20:04:44 +000029#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <errno.h>
Jon Griffiths4ab15582001-01-22 02:17:29 +000033#include <string.h>
Chris Morganb9807b42001-02-15 21:24:07 +000034#include <time.h>
Ulrich Czekallac2757242000-06-11 20:04:44 +000035
Guy Albertelliaafec982001-11-06 22:31:19 +000036#include "windef.h"
37#include "winbase.h"
38#include "wininet.h"
39#include "winreg.h"
40#include "winerror.h"
Jon Griffiths603f20f2001-12-11 00:30:17 +000041#define NO_SHLWAPI_STREAM
Guy Albertelliaafec982001-11-06 22:31:19 +000042#include "shlwapi.h"
43
Ulrich Czekallac2757242000-06-11 20:04:44 +000044#include "internet.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000045#include "wine/debug.h"
Ulrich Czekallac2757242000-06-11 20:04:44 +000046
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000047WINE_DEFAULT_DEBUG_CHANNEL(wininet);
Ulrich Czekallac2757242000-06-11 20:04:44 +000048
49#define HTTPHEADER " HTTP/1.0"
50#define HTTPHOSTHEADER "\r\nHost: "
51#define MAXHOSTNAME 100
52#define MAX_FIELD_VALUE_LEN 256
53#define MAX_FIELD_LEN 256
54
55
56#define HTTP_REFERER "Referer"
57#define HTTP_ACCEPT "Accept"
58
59#define HTTP_ADDHDR_FLAG_ADD 0x20000000
60#define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
61#define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
62#define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
63#define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
64#define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
65#define HTTP_ADDHDR_FLAG_REQ 0x02000000
66
67
68BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr);
Vincent Béron9a624912002-05-31 23:06:46 +000069int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr,
Ulrich Czekallac2757242000-06-11 20:04:44 +000070 void *Buffer, int BytesToWrite);
Vincent Béron9a624912002-05-31 23:06:46 +000071int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr,
Ulrich Czekallac2757242000-06-11 20:04:44 +000072 void *Buffer, int BytesToRead);
73BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr);
74BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier);
75void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr);
76BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen);
77INT HTTP_GetStdHeaderIndex(LPCSTR lpszField);
78INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr);
79INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField);
80
Alexandre Julliard0e44f632000-11-16 00:28:52 +000081inline static LPSTR HTTP_strdup( LPCSTR str )
82{
83 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
84 if (ret) strcpy( ret, str );
85 return ret;
86}
87
Ulrich Czekallac2757242000-06-11 20:04:44 +000088/***********************************************************************
Patrik Stridvall8b216b32001-06-19 18:20:47 +000089 * HttpAddRequestHeadersA (WININET.@)
Ulrich Czekallac2757242000-06-11 20:04:44 +000090 *
91 * Adds one or more HTTP header to the request handler
92 *
93 * RETURNS
94 * TRUE on success
95 * FALSE on failure
96 *
97 */
Vincent Béron9a624912002-05-31 23:06:46 +000098BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
Ulrich Czekallac2757242000-06-11 20:04:44 +000099 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
100{
101 LPSTR lpszStart;
102 LPSTR lpszEnd;
103 LPSTR buffer;
104 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
105 BOOL bSuccess = FALSE;
106 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
107
108 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
109 {
110 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
111 return FALSE;
112 }
113
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000114 buffer = HTTP_strdup(lpszHeader);
Ulrich Czekallac2757242000-06-11 20:04:44 +0000115 lpszStart = buffer;
116
117 do
118 {
119 lpszEnd = lpszStart;
120
121 while (*lpszEnd != '\0')
122 {
123 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
124 break;
125 lpszEnd++;
126 }
127
128 if (*lpszEnd == '\0')
129 break;
130
131 *lpszEnd = '\0';
132
133 if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
134 bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
135
136 lpszStart = lpszEnd + 2; /* Jump over \0\n */
137
138 } while (bSuccess);
139
140 HeapFree(GetProcessHeap(), 0, buffer);
141 return bSuccess;
142}
143
144
145/***********************************************************************
Patrik Stridvall8b216b32001-06-19 18:20:47 +0000146 * HttpOpenRequestA (WININET.@)
Ulrich Czekallac2757242000-06-11 20:04:44 +0000147 *
148 * Open a HTTP request handle
149 *
150 * RETURNS
151 * HINTERNET a HTTP request handle on success
152 * NULL on failure
153 *
154 */
Patrik Stridvall3c0211f2001-09-11 00:32:32 +0000155HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
Ulrich Czekallac2757242000-06-11 20:04:44 +0000156 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
Vincent Béron9a624912002-05-31 23:06:46 +0000157 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
Ulrich Czekallac2757242000-06-11 20:04:44 +0000158 DWORD dwFlags, DWORD dwContext)
159{
160 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
161 LPWININETAPPINFOA hIC = NULL;
162
163 TRACE("\n");
164
165 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
166 {
167 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
168 return FALSE;
169 }
170
171 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
172
173 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
174 {
175 WORKREQUEST workRequest;
176
177 workRequest.asyncall = HTTPOPENREQUESTA;
178 workRequest.HFTPSESSION = (DWORD)hHttpSession;
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000179 workRequest.LPSZVERB = (DWORD)HTTP_strdup(lpszVerb);
180 workRequest.LPSZOBJECTNAME = (DWORD)HTTP_strdup(lpszObjectName);
181 workRequest.LPSZVERSION = (DWORD)HTTP_strdup(lpszVersion);
182 workRequest.LPSZREFERRER = (DWORD)HTTP_strdup(lpszReferrer);
Ulrich Czekallac2757242000-06-11 20:04:44 +0000183 workRequest.LPSZACCEPTTYPES = (DWORD)lpszAcceptTypes;
184 workRequest.DWFLAGS = dwFlags;
185 workRequest.DWCONTEXT = dwContext;
186
187 return (HINTERNET)INTERNET_AsyncCall(&workRequest);
188 }
189 else
190 {
Vincent Béron9a624912002-05-31 23:06:46 +0000191 return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
Ulrich Czekallac2757242000-06-11 20:04:44 +0000192 lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext);
193 }
194}
195
196
197/***********************************************************************
198 * HTTP_HttpOpenRequestA (internal)
199 *
200 * Open a HTTP request handle
201 *
202 * RETURNS
203 * HINTERNET a HTTP request handle on success
204 * NULL on failure
205 *
206 */
Patrik Stridvall3c0211f2001-09-11 00:32:32 +0000207HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
Ulrich Czekallac2757242000-06-11 20:04:44 +0000208 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
Vincent Béron9a624912002-05-31 23:06:46 +0000209 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
Ulrich Czekallac2757242000-06-11 20:04:44 +0000210 DWORD dwFlags, DWORD dwContext)
211{
212 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
213 LPWININETAPPINFOA hIC = NULL;
214 LPWININETHTTPREQA lpwhr;
215
216 TRACE("\n");
217
218 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
219 {
220 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
221 return FALSE;
222 }
223
224 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
225
226 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
227 if (NULL == lpwhr)
228 {
229 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
230 return (HINTERNET) NULL;
231 }
232
233 lpwhr->hdr.htype = WH_HHTTPREQ;
234 lpwhr->hdr.lpwhparent = hHttpSession;
235 lpwhr->hdr.dwFlags = dwFlags;
236 lpwhr->hdr.dwContext = dwContext;
Francois Gougeta0f98f12001-08-24 19:13:36 +0000237 lpwhr->nSocketFD = -1;
Ulrich Czekallac2757242000-06-11 20:04:44 +0000238
Huw D M Davies0aebee92001-01-21 21:09:00 +0000239 if (NULL != lpszObjectName && strlen(lpszObjectName)) {
240 DWORD needed = 0;
241 UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
242 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
243 UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
244 URL_ESCAPE_SPACES_ONLY);
245 }
Ulrich Czekallac2757242000-06-11 20:04:44 +0000246
247 if (NULL != lpszReferrer && strlen(lpszReferrer))
248 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
249
Patrik Stridvallfc2be7e2002-04-29 18:48:56 +0000250 /* FIXME */
Ulrich Czekallac2757242000-06-11 20:04:44 +0000251 if (NULL != lpszAcceptTypes && strlen(*lpszAcceptTypes))
252 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, *lpszAcceptTypes, HTTP_ADDHDR_FLAG_COALESCE);
253
254 if (NULL == lpszVerb)
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000255 lpwhr->lpszVerb = HTTP_strdup("GET");
Ulrich Czekallac2757242000-06-11 20:04:44 +0000256 else if (strlen(lpszVerb))
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000257 lpwhr->lpszVerb = HTTP_strdup(lpszVerb);
Ulrich Czekallac2757242000-06-11 20:04:44 +0000258
259 if (NULL != lpszReferrer)
260 {
261 char buf[MAXHOSTNAME];
262 URL_COMPONENTSA UrlComponents;
263
264 UrlComponents.lpszExtraInfo = NULL;
265 UrlComponents.lpszPassword = NULL;
266 UrlComponents.lpszScheme = NULL;
267 UrlComponents.lpszUrlPath = NULL;
268 UrlComponents.lpszUserName = NULL;
269 UrlComponents.lpszHostName = buf;
270 UrlComponents.dwHostNameLength = MAXHOSTNAME;
271
272 InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
273 if (strlen(UrlComponents.lpszHostName))
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000274 lpwhr->lpszHostName = HTTP_strdup(UrlComponents.lpszHostName);
Andreas Mohr34965562000-08-26 20:31:48 +0000275 } else {
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000276 lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName);
Ulrich Czekallac2757242000-06-11 20:04:44 +0000277 }
278
279 if (hIC->lpfnStatusCB)
280 {
281 INTERNET_ASYNC_RESULT iar;
282
283 iar.dwResult = (DWORD)lpwhr;
284 iar.dwError = ERROR_SUCCESS;
285
286 hIC->lpfnStatusCB(hHttpSession, dwContext, INTERNET_STATUS_HANDLE_CREATED,
287 &iar, sizeof(INTERNET_ASYNC_RESULT));
288 }
289
290 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
291 {
292 INTERNET_ASYNC_RESULT iar;
Vincent Béron9a624912002-05-31 23:06:46 +0000293
Ulrich Czekallac2757242000-06-11 20:04:44 +0000294 iar.dwResult = (DWORD)lpwhr;
295 iar.dwError = lpwhr ? ERROR_SUCCESS : INTERNET_GetLastError();
296 hIC->lpfnStatusCB(hHttpSession, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
297 &iar, sizeof(INTERNET_ASYNC_RESULT));
298 }
299
300 return (HINTERNET) lpwhr;
301}
302
303
304/***********************************************************************
Patrik Stridvall8b216b32001-06-19 18:20:47 +0000305 * HttpQueryInfoA (WININET.@)
Ulrich Czekallac2757242000-06-11 20:04:44 +0000306 *
307 * Queries for information about an HTTP request
308 *
309 * RETURNS
310 * TRUE on success
311 * FALSE on failure
312 *
313 */
314BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
315 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
316{
Vincent Béron9a624912002-05-31 23:06:46 +0000317 LPHTTPHEADERA lphttpHdr = NULL;
Ulrich Czekallac2757242000-06-11 20:04:44 +0000318 BOOL bSuccess = FALSE;
319 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
Vincent Béron9a624912002-05-31 23:06:46 +0000320
Ulrich Czekallac2757242000-06-11 20:04:44 +0000321 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel, dwInfoLevel);
322
323 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
324 {
325 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
326 return FALSE;
327 }
328
329 /* Find requested header structure */
330 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
331 {
332 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
333
334 if (index < 0)
335 goto lend;
336
337 lphttpHdr = &lpwhr->pCustHeaders[index];
338 }
339 else
340 {
341 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
342
343 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
344 {
345 INT i, delim, size = 0, cnt = 0;
346
347 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
348
349 /* Calculate length of custom reuqest headers */
350 for (i = 0; i < lpwhr->nCustHeaders; i++)
351 {
352 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
353 lpwhr->pCustHeaders[i].lpszValue)
354 {
Vincent Béron9a624912002-05-31 23:06:46 +0000355 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
Ulrich Czekallac2757242000-06-11 20:04:44 +0000356 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
357 }
358 }
359
360 /* Calculate the length of stadard request headers */
361 for (i = 0; i <= HTTP_QUERY_MAX; i++)
362 {
Vincent Béron9a624912002-05-31 23:06:46 +0000363 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
Ulrich Czekallac2757242000-06-11 20:04:44 +0000364 lpwhr->StdHeaders[i].lpszValue)
365 {
Vincent Béron9a624912002-05-31 23:06:46 +0000366 size += strlen(lpwhr->StdHeaders[i].lpszField) +
Ulrich Czekallac2757242000-06-11 20:04:44 +0000367 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
368 }
369 }
370
371 size += delim;
372
373 if (size + 1 > *lpdwBufferLength)
374 {
375 *lpdwBufferLength = size + 1;
376 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
377 goto lend;
378 }
379
380 /* Append standard request heades */
381 for (i = 0; i <= HTTP_QUERY_MAX; i++)
382 {
383 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
384 lpwhr->StdHeaders[i].lpszField &&
385 lpwhr->StdHeaders[i].lpszValue)
386 {
387 cnt += sprintf(lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
388 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
389 }
390 }
391
392 /* Append custom request heades */
393 for (i = 0; i < lpwhr->nCustHeaders; i++)
394 {
395 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
396 lpwhr->pCustHeaders[i].lpszField &&
397 lpwhr->pCustHeaders[i].lpszValue)
398 {
Vincent Béron9a624912002-05-31 23:06:46 +0000399 cnt += sprintf(lpBuffer + cnt, "%s: %s%s",
Ulrich Czekallac2757242000-06-11 20:04:44 +0000400 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
401 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
402 }
403 }
404
405 strcpy(lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
406
407 *lpdwBufferLength = cnt + delim;
408 bSuccess = TRUE;
409 goto lend;
410 }
411 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
Vincent Béron9a624912002-05-31 23:06:46 +0000412 {
Ulrich Czekallac2757242000-06-11 20:04:44 +0000413 lphttpHdr = &lpwhr->StdHeaders[index];
414 }
415 else
416 goto lend;
417 }
418
419 /* Ensure header satisifies requested attributes */
Vincent Béron9a624912002-05-31 23:06:46 +0000420 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
Ulrich Czekallac2757242000-06-11 20:04:44 +0000421 (~lphttpHdr->wFlags & HDR_ISREQUEST))
422 goto lend;
Vincent Béron9a624912002-05-31 23:06:46 +0000423
Ulrich Czekallac2757242000-06-11 20:04:44 +0000424 /* coalesce value to reuqested type */
425 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
426 {
427 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
428 bSuccess = TRUE;
429 }
430 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
431 {
432 time_t tmpTime;
433 struct tm tmpTM;
434 SYSTEMTIME *STHook;
Vincent Béron9a624912002-05-31 23:06:46 +0000435
Ulrich Czekallac2757242000-06-11 20:04:44 +0000436 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
437
438 tmpTM = *gmtime(&tmpTime);
439 STHook = (SYSTEMTIME *) lpBuffer;
440 if(STHook==NULL)
441 goto lend;
442
443 STHook->wDay = tmpTM.tm_mday;
444 STHook->wHour = tmpTM.tm_hour;
445 STHook->wMilliseconds = 0;
446 STHook->wMinute = tmpTM.tm_min;
447 STHook->wDayOfWeek = tmpTM.tm_wday;
448 STHook->wMonth = tmpTM.tm_mon + 1;
449 STHook->wSecond = tmpTM.tm_sec;
450 STHook->wYear = tmpTM.tm_year;
451
452 bSuccess = TRUE;
453 }
454 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
455 {
456 if (*lpdwIndex >= lphttpHdr->wCount)
457 {
458 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
459 }
460 else
461 {
Patrik Stridvallfc2be7e2002-04-29 18:48:56 +0000462 /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
Ulrich Czekallac2757242000-06-11 20:04:44 +0000463 (*lpdwIndex)++;
464 }
465 }
466 else
467 {
468 INT len = strlen(lphttpHdr->lpszValue);
469
470 if (len + 1 > *lpdwBufferLength)
471 {
472 *lpdwBufferLength = len + 1;
473 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
474 goto lend;
475 }
476
477 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
478 *lpdwBufferLength = len;
Vincent Béron9a624912002-05-31 23:06:46 +0000479 bSuccess = TRUE;
Ulrich Czekallac2757242000-06-11 20:04:44 +0000480 }
481
482lend:
483 TRACE("%d <--\n", bSuccess);
484 return bSuccess;
485}
486
Huw D M Daviesf9b6d7b2000-10-28 00:30:23 +0000487
488/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +0000489 * HttpSendRequestExA (WININET.@)
Huw D M Daviesf9b6d7b2000-10-28 00:30:23 +0000490 *
491 * Sends the specified request to the HTTP server and allows chunked
492 * transfers
493 */
494BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
495 LPINTERNET_BUFFERSA lpBuffersIn,
496 LPINTERNET_BUFFERSA lpBuffersOut,
497 DWORD dwFlags, DWORD dwContext)
498{
499 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
500 lpBuffersOut, dwFlags, dwContext);
501 return FALSE;
502}
503
Ulrich Czekallac2757242000-06-11 20:04:44 +0000504/***********************************************************************
Patrik Stridvall8b216b32001-06-19 18:20:47 +0000505 * HttpSendRequestA (WININET.@)
Ulrich Czekallac2757242000-06-11 20:04:44 +0000506 *
507 * Sends the specified request to the HTTP server
508 *
509 * RETURNS
510 * TRUE on success
511 * FALSE on failure
512 *
513 */
514BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
515 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
Vincent Béron9a624912002-05-31 23:06:46 +0000516{
Ulrich Czekallac2757242000-06-11 20:04:44 +0000517 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
518 LPWININETHTTPSESSIONA lpwhs = NULL;
519 LPWININETAPPINFOA hIC = NULL;
520
521 TRACE("0x%08lx\n", (unsigned long)hHttpRequest);
522
523 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
524 {
525 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
526 return FALSE;
527 }
528
529 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
530 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
531 {
532 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
533 return FALSE;
534 }
535
536 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
537 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
538 {
539 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
540 return FALSE;
541 }
542
543 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
544 {
545 WORKREQUEST workRequest;
546
547 workRequest.asyncall = HTTPSENDREQUESTA;
548 workRequest.HFTPSESSION = (DWORD)hHttpRequest;
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000549 workRequest.LPSZHEADER = (DWORD)HTTP_strdup(lpszHeaders);
Ulrich Czekallac2757242000-06-11 20:04:44 +0000550 workRequest.DWHEADERLENGTH = dwHeaderLength;
551 workRequest.LPOPTIONAL = (DWORD)lpOptional;
552 workRequest.DWOPTIONALLENGTH = dwOptionalLength;
553
554 return INTERNET_AsyncCall(&workRequest);
555 }
556 else
557 {
Vincent Béron9a624912002-05-31 23:06:46 +0000558 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
Ulrich Czekallac2757242000-06-11 20:04:44 +0000559 dwHeaderLength, lpOptional, dwOptionalLength);
560 }
561}
562
563
564/***********************************************************************
565 * HTTP_HttpSendRequestA (internal)
566 *
567 * Sends the specified request to the HTTP server
568 *
569 * RETURNS
570 * TRUE on success
571 * FALSE on failure
572 *
573 */
574BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
575 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
576{
577 INT cnt;
578 INT i;
579 BOOL bSuccess = FALSE;
580 LPSTR requestString = NULL;
581 INT requestStringLen;
582 INT headerLength = 0;
583 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
584 LPWININETHTTPSESSIONA lpwhs = NULL;
585 LPWININETAPPINFOA hIC = NULL;
586
587 TRACE("0x%08lx\n", (ULONG)hHttpRequest);
588
589 /* Verify our tree of internet handles */
590 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
591 {
592 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
593 return FALSE;
594 }
595
596 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
597 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
598 {
599 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
600 return FALSE;
601 }
602
603 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
604 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
605 {
606 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
607 return FALSE;
608 }
609
610 /* Clear any error information */
611 INTERNET_SetLastError(0);
612
613 /* We must have a verb */
614 if (NULL == lpwhr->lpszVerb)
615 {
616 goto lend;
617 }
618
619 /* If we don't have a path we set it to root */
620 if (NULL == lpwhr->lpszPath)
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000621 lpwhr->lpszPath = HTTP_strdup("/");
Ulrich Czekallac2757242000-06-11 20:04:44 +0000622
Nikolas Zimmermann76598822001-10-04 18:12:41 +0000623 if(lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
624 {
625 char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2);
626 *fixurl = '/';
627 strcpy(fixurl + 1, lpwhr->lpszPath);
628 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
629 lpwhr->lpszPath = fixurl;
630 }
631
Ulrich Czekallac2757242000-06-11 20:04:44 +0000632 /* Calculate length of request string */
Vincent Béron9a624912002-05-31 23:06:46 +0000633 requestStringLen =
Ulrich Czekallac2757242000-06-11 20:04:44 +0000634 strlen(lpwhr->lpszVerb) +
635 strlen(lpwhr->lpszPath) +
636 (lpwhr->lpszHostName ? (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)) : 0) +
637 strlen(HTTPHEADER) +
638 5; /* " \r\n\r\n" */
639
640 /* Add length of passed headers */
641 if (lpszHeaders)
642 {
Vincent Béron9a624912002-05-31 23:06:46 +0000643 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength;
Ulrich Czekallac2757242000-06-11 20:04:44 +0000644 requestStringLen += headerLength + 2; /* \r\n */
645 }
646
John R. Sheets646d2a22000-07-23 13:34:43 +0000647 /* Calculate length of custom request headers */
Ulrich Czekallac2757242000-06-11 20:04:44 +0000648 for (i = 0; i < lpwhr->nCustHeaders; i++)
649 {
650 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
651 {
Vincent Béron9a624912002-05-31 23:06:46 +0000652 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
Ulrich Czekallac2757242000-06-11 20:04:44 +0000653 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
654 }
655 }
656
John R. Sheets646d2a22000-07-23 13:34:43 +0000657 /* Calculate the length of standard request headers */
Ulrich Czekallac2757242000-06-11 20:04:44 +0000658 for (i = 0; i <= HTTP_QUERY_MAX; i++)
659 {
660 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
661 {
Vincent Béron9a624912002-05-31 23:06:46 +0000662 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
Ulrich Czekallac2757242000-06-11 20:04:44 +0000663 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
664 }
665 }
666
667 /* Allocate string to hold entire request */
668 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
669 if (NULL == requestString)
670 {
671 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
672 goto lend;
673 }
674
675 /* Build request string */
676 cnt = sprintf(requestString, "%s %s%s%s",
677 lpwhr->lpszVerb,
678 lpwhr->lpszPath,
679 lpwhr->lpszHostName ? (HTTPHEADER HTTPHOSTHEADER) : HTTPHEADER,
680 lpwhr->lpszHostName ? lpwhr->lpszHostName : "");
681
John R. Sheets646d2a22000-07-23 13:34:43 +0000682 /* Append standard request headers */
Ulrich Czekallac2757242000-06-11 20:04:44 +0000683 for (i = 0; i <= HTTP_QUERY_MAX; i++)
684 {
685 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
686 {
Vincent Béron9a624912002-05-31 23:06:46 +0000687 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
Ulrich Czekallac2757242000-06-11 20:04:44 +0000688 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
689 }
690 }
691
692 /* Append custom request heades */
693 for (i = 0; i < lpwhr->nCustHeaders; i++)
694 {
695 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
696 {
Vincent Béron9a624912002-05-31 23:06:46 +0000697 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
Ulrich Czekallac2757242000-06-11 20:04:44 +0000698 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
699 }
700 }
701
702 /* Append passed request headers */
703 if (lpszHeaders)
704 {
705 strcpy(requestString + cnt, "\r\n");
706 cnt += 2;
707 strcpy(requestString + cnt, lpszHeaders);
708 cnt += headerLength;
709 }
710
711 /* Set termination string for request */
712 strcpy(requestString + cnt, "\r\n\r\n");
713
714 if (hIC->lpfnStatusCB)
715 hIC->lpfnStatusCB(hHttpRequest, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
716
717 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
718 /* Send the request and store the results */
719 if (!HTTP_OpenConnection(lpwhr))
720 goto lend;
721
722 cnt = INTERNET_WriteDataToStream(lpwhr->nSocketFD, requestString, requestStringLen);
723
724 if (cnt < 0)
725 goto lend;
726
727 if (HTTP_GetResponseHeaders(lpwhr))
728 bSuccess = TRUE;
729
730lend:
731
732 if (requestString)
733 HeapFree(GetProcessHeap(), 0, requestString);
734
735 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
736 {
737 INTERNET_ASYNC_RESULT iar;
Vincent Béron9a624912002-05-31 23:06:46 +0000738
Ulrich Czekallac2757242000-06-11 20:04:44 +0000739 iar.dwResult = (DWORD)bSuccess;
740 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
741 hIC->lpfnStatusCB(hHttpRequest, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
742 &iar, sizeof(INTERNET_ASYNC_RESULT));
743 }
744
745 TRACE("<--\n");
746 return bSuccess;
747}
748
749
750/***********************************************************************
751 * HTTP_Connect (internal)
752 *
753 * Create http session handle
754 *
755 * RETURNS
756 * HINTERNET a session handle on success
757 * NULL on failure
758 *
759 */
Vincent Béron9a624912002-05-31 23:06:46 +0000760HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
Ulrich Czekallac2757242000-06-11 20:04:44 +0000761 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
762 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
763{
764 BOOL bSuccess = FALSE;
765 LPWININETAPPINFOA hIC = NULL;
766 LPWININETHTTPSESSIONA lpwhs = NULL;
767
768 TRACE("\n");
769
770 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
771 goto lerror;
772
773 hIC = (LPWININETAPPINFOA) hInternet;
774
775 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
776 if (NULL == lpwhs)
777 {
778 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
779 goto lerror;
780 }
781
782 if (hIC->lpfnStatusCB)
783 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
Patrik Stridvall4710be22000-06-23 15:47:14 +0000784 (LPVOID)lpszServerName, strlen(lpszServerName));
Ulrich Czekallac2757242000-06-11 20:04:44 +0000785
786 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
787 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
788
789 if (!GetAddress(lpszServerName, nServerPort, &lpwhs->phostent, &lpwhs->socketAddress))
790 {
791 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
792 goto lerror;
793 }
794
795 if (hIC->lpfnStatusCB)
796 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
Patrik Stridvall4710be22000-06-23 15:47:14 +0000797 (LPVOID)lpszServerName, strlen(lpszServerName));
Ulrich Czekallac2757242000-06-11 20:04:44 +0000798
799 lpwhs->hdr.htype = WH_HHTTPSESSION;
800 lpwhs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
801 lpwhs->hdr.dwFlags = dwFlags;
802 lpwhs->hdr.dwContext = dwContext;
803 if (NULL != lpszServerName)
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000804 lpwhs->lpszServerName = HTTP_strdup(lpszServerName);
Ulrich Czekallac2757242000-06-11 20:04:44 +0000805 if (NULL != lpszUserName)
Alexandre Julliard0e44f632000-11-16 00:28:52 +0000806 lpwhs->lpszUserName = HTTP_strdup(lpszUserName);
Ulrich Czekallac2757242000-06-11 20:04:44 +0000807 lpwhs->nServerPort = nServerPort;
808
809 if (hIC->lpfnStatusCB)
810 {
811 INTERNET_ASYNC_RESULT iar;
812
813 iar.dwResult = (DWORD)lpwhs;
814 iar.dwError = ERROR_SUCCESS;
815
816 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
817 &iar, sizeof(INTERNET_ASYNC_RESULT));
818 }
819
820 bSuccess = TRUE;
821
822lerror:
823 if (!bSuccess && lpwhs)
824 {
825 HeapFree(GetProcessHeap(), 0, lpwhs);
826 lpwhs = NULL;
827 }
828
829 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
830 {
831 INTERNET_ASYNC_RESULT iar;
Vincent Béron9a624912002-05-31 23:06:46 +0000832
Ulrich Czekallac2757242000-06-11 20:04:44 +0000833 iar.dwResult = (DWORD)lpwhs;
834 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
835 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
836 &iar, sizeof(INTERNET_ASYNC_RESULT));
837 }
838TRACE("<--\n");
839 return (HINTERNET)lpwhs;
840}
841
842
843/***********************************************************************
844 * HTTP_OpenConnection (internal)
845 *
846 * Connect to a web server
847 *
848 * RETURNS
849 *
850 * TRUE on success
851 * FALSE on failure
852 */
853BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
854{
855 BOOL bSuccess = FALSE;
856 INT result;
857 LPWININETHTTPSESSIONA lpwhs;
858
859 TRACE("\n");
860
861 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
862 {
863 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
864 goto lend;
865 }
866
867 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
868
869 lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0);
Francois Gougeta0f98f12001-08-24 19:13:36 +0000870 if (lpwhr->nSocketFD == -1)
Ulrich Czekallac2757242000-06-11 20:04:44 +0000871 {
872 WARN("Socket creation failed\n");
873 goto lend;
874 }
875
876 result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress,
877 sizeof(lpwhs->socketAddress));
878
Francois Gougeta0f98f12001-08-24 19:13:36 +0000879 if (result == -1)
Ulrich Czekallac2757242000-06-11 20:04:44 +0000880 {
Andreas Mohr34965562000-08-26 20:31:48 +0000881 WARN("Unable to connect to host (%s)\n", strerror(errno));
Ulrich Czekallac2757242000-06-11 20:04:44 +0000882 goto lend;
883 }
884
885 bSuccess = TRUE;
886
887lend:
888 TRACE(": %d\n", bSuccess);
889 return bSuccess;
890}
891
892
893/***********************************************************************
894 * HTTP_GetResponseHeaders (internal)
895 *
896 * Read server response
897 *
898 * RETURNS
899 *
900 * TRUE on success
901 * FALSE on error
902 */
903BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
904{
905 INT cbreaks = 0;
906 CHAR buffer[MAX_REPLY_LEN];
907 DWORD buflen = MAX_REPLY_LEN;
908 BOOL bSuccess = FALSE;
909 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
910
911 TRACE("\n");
912
Francois Gougeta0f98f12001-08-24 19:13:36 +0000913 if (lpwhr->nSocketFD == -1)
Ulrich Czekallac2757242000-06-11 20:04:44 +0000914 goto lend;
915
Vincent Béron9a624912002-05-31 23:06:46 +0000916 /*
Ulrich Czekallac2757242000-06-11 20:04:44 +0000917 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
918 */
919 if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
920 goto lend;
921
922 if (strncmp(buffer, "HTTP", 4) != 0)
923 goto lend;
Vincent Béron9a624912002-05-31 23:06:46 +0000924
Ulrich Czekallac2757242000-06-11 20:04:44 +0000925 buffer[12]='\0';
926 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
927
928 /* Parse each response line */
929 do
930 {
931 buflen = MAX_REPLY_LEN;
932 if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
933 {
934 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
935 break;
936
937 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
938 }
939 else
940 {
941 cbreaks++;
942 if (cbreaks >= 2)
943 break;
944 }
945 }while(1);
946
947 bSuccess = TRUE;
948
949lend:
950
951 return bSuccess;
952}
953
954
955/***********************************************************************
956 * HTTP_InterpretHttpHeader (internal)
957 *
958 * Parse server response
959 *
960 * RETURNS
961 *
962 * TRUE on success
963 * FALSE on error
964 */
965INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
966{
967 LPCSTR lpsztmp;
968 INT srclen;
969
970 srclen = 0;
971
972 while (*lpszSrc == ' ' && *lpszSrc != '\0')
973 lpszSrc++;
Vincent Béron9a624912002-05-31 23:06:46 +0000974
Ulrich Czekallac2757242000-06-11 20:04:44 +0000975 lpsztmp = lpszSrc;
976 while(*lpsztmp != '\0')
977 {
978 if (*lpsztmp != ' ')
979 srclen = lpsztmp - lpszSrc + 1;
980
981 lpsztmp++;
982 }
983
984 *len = min(*len, srclen);
985 strncpy(lpszStart, lpszSrc, *len);
986 lpszStart[*len] = '\0';
987
988 return *len;
989}
990
991
992BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
993{
994 CHAR *pd;
995 BOOL bSuccess = FALSE;
996
997 TRACE("\n");
998
999 *field = '\0';
1000 *value = '\0';
1001
1002 pd = strchr(buffer, ':');
1003 if (pd)
1004 {
1005 *pd = '\0';
1006 if (stripSpaces(buffer, field, &fieldlen) > 0)
1007 {
1008 if (stripSpaces(pd+1, value, &valuelen) > 0)
1009 bSuccess = TRUE;
1010 }
1011 }
1012
1013 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
1014 return bSuccess;
1015}
1016
1017
1018/***********************************************************************
1019 * HTTP_GetStdHeaderIndex (internal)
1020 *
John R. Sheets646d2a22000-07-23 13:34:43 +00001021 * Lookup field index in standard http header array
Ulrich Czekallac2757242000-06-11 20:04:44 +00001022 *
1023 * FIXME: This should be stuffed into a hash table
1024 */
1025INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1026{
1027 INT index = -1;
1028
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001029 if (!strcasecmp(lpszField, "Content-Length"))
Ulrich Czekallac2757242000-06-11 20:04:44 +00001030 index = HTTP_QUERY_CONTENT_LENGTH;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001031 else if (!strcasecmp(lpszField,"Status"))
Ulrich Czekallac2757242000-06-11 20:04:44 +00001032 index = HTTP_QUERY_STATUS_CODE;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001033 else if (!strcasecmp(lpszField,"Content-Type"))
Ulrich Czekallac2757242000-06-11 20:04:44 +00001034 index = HTTP_QUERY_CONTENT_TYPE;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001035 else if (!strcasecmp(lpszField,"Last-Modified"))
Ulrich Czekallac2757242000-06-11 20:04:44 +00001036 index = HTTP_QUERY_LAST_MODIFIED;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001037 else if (!strcasecmp(lpszField,"Location"))
Ulrich Czekallac2757242000-06-11 20:04:44 +00001038 index = HTTP_QUERY_LOCATION;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001039 else if (!strcasecmp(lpszField,"Accept"))
Ulrich Czekallac2757242000-06-11 20:04:44 +00001040 index = HTTP_QUERY_ACCEPT;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001041 else if (!strcasecmp(lpszField,"Referer"))
Ulrich Czekallac2757242000-06-11 20:04:44 +00001042 index = HTTP_QUERY_REFERER;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001043 else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
Ulrich Czekallac2757242000-06-11 20:04:44 +00001044 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001045 else if (!strcasecmp(lpszField,"Date"))
John R. Sheets646d2a22000-07-23 13:34:43 +00001046 index = HTTP_QUERY_DATE;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001047 else if (!strcasecmp(lpszField,"Server"))
John R. Sheets646d2a22000-07-23 13:34:43 +00001048 index = HTTP_QUERY_SERVER;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001049 else if (!strcasecmp(lpszField,"Connection"))
John R. Sheets646d2a22000-07-23 13:34:43 +00001050 index = HTTP_QUERY_CONNECTION;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001051 else if (!strcasecmp(lpszField,"ETag"))
John R. Sheets646d2a22000-07-23 13:34:43 +00001052 index = HTTP_QUERY_ETAG;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001053 else if (!strcasecmp(lpszField,"Accept-Ranges"))
John R. Sheets646d2a22000-07-23 13:34:43 +00001054 index = HTTP_QUERY_ACCEPT_RANGES;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001055 else if (!strcasecmp(lpszField,"Expires"))
John R. Sheets646d2a22000-07-23 13:34:43 +00001056 index = HTTP_QUERY_EXPIRES;
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001057 else if (!strcasecmp(lpszField,"Mime-Version"))
John R. Sheets66b4dd22000-08-03 22:16:39 +00001058 index = HTTP_QUERY_MIME_VERSION;
Johan Dahlin664b9bb2001-12-17 20:50:53 +00001059 else if (!strcasecmp(lpszField,"Pragma"))
1060 index = HTTP_QUERY_PRAGMA;
1061 else if (!strcasecmp(lpszField,"Cache-Control"))
1062 index = HTTP_QUERY_CACHE_CONTROL;
1063 else if (!strcasecmp(lpszField,"Content-Length"))
1064 index = HTTP_QUERY_CONTENT_LENGTH;
1065 else if (!strcasecmp(lpszField,"User-Agent"))
1066 index = HTTP_QUERY_USER_AGENT;
Ulrich Czekallac2757242000-06-11 20:04:44 +00001067 else
1068 {
1069 FIXME("Couldn't find %s in standard header table\n", lpszField);
1070 }
1071
1072 return index;
1073}
1074
1075
1076/***********************************************************************
1077 * HTTP_ProcessHeader (internal)
1078 *
1079 * Stuff header into header tables according to <dwModifier>
1080 *
1081 */
1082
1083#define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1084
1085BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
1086{
1087 LPHTTPHEADERA lphttpHdr = NULL;
1088 BOOL bSuccess = FALSE;
1089 INT index;
1090
1091 TRACE("%s:%s - 0x%08x\n", field, value, (unsigned int)dwModifier);
1092
1093 /* Adjust modifier flags */
1094 if (dwModifier & COALESCEFLASG)
1095 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
1096
1097 /* Try to get index into standard header array */
1098 index = HTTP_GetStdHeaderIndex(field);
1099 if (index >= 0)
1100 {
1101 lphttpHdr = &lpwhr->StdHeaders[index];
1102 }
1103 else /* Find or create new custom header */
1104 {
1105 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
1106 if (index >= 0)
1107 {
1108 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
1109 {
1110 return FALSE;
1111 }
1112 lphttpHdr = &lpwhr->pCustHeaders[index];
1113 }
1114 else
1115 {
1116 HTTPHEADERA hdr;
1117
Patrik Stridvall4710be22000-06-23 15:47:14 +00001118 hdr.lpszField = (LPSTR)field;
1119 hdr.lpszValue = (LPSTR)value;
Ulrich Czekallac2757242000-06-11 20:04:44 +00001120 hdr.wFlags = hdr.wCount = 0;
1121
1122 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1123 hdr.wFlags |= HDR_ISREQUEST;
1124
1125 index = HTTP_InsertCustomHeader(lpwhr, &hdr);
1126 return index >= 0;
1127 }
1128 }
Vincent Béron9a624912002-05-31 23:06:46 +00001129
Ulrich Czekallac2757242000-06-11 20:04:44 +00001130 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1131 lphttpHdr->wFlags |= HDR_ISREQUEST;
1132 else
1133 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
Vincent Béron9a624912002-05-31 23:06:46 +00001134
Ulrich Czekallac2757242000-06-11 20:04:44 +00001135 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
1136 {
1137 INT slen;
1138
1139 if (!lpwhr->StdHeaders[index].lpszField)
1140 {
Alexandre Julliard0e44f632000-11-16 00:28:52 +00001141 lphttpHdr->lpszField = HTTP_strdup(field);
Ulrich Czekallac2757242000-06-11 20:04:44 +00001142
1143 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1144 lphttpHdr->wFlags |= HDR_ISREQUEST;
1145 }
1146
1147 slen = strlen(value) + 1;
1148 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
1149 if (lphttpHdr->lpszValue)
1150 {
1151 memcpy(lphttpHdr->lpszValue, value, slen);
1152 bSuccess = TRUE;
1153 }
1154 else
1155 {
1156 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1157 }
1158 }
Vincent Béron9a624912002-05-31 23:06:46 +00001159 else if (lphttpHdr->lpszValue)
Ulrich Czekallac2757242000-06-11 20:04:44 +00001160 {
Vincent Béron9a624912002-05-31 23:06:46 +00001161 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
Ulrich Czekallac2757242000-06-11 20:04:44 +00001162 {
1163 LPSTR lpsztmp;
1164 INT len;
1165
1166 len = strlen(value);
1167
1168 if (len <= 0)
1169 {
Patrik Stridvallfc2be7e2002-04-29 18:48:56 +00001170 /* if custom header delete from array */
Ulrich Czekallac2757242000-06-11 20:04:44 +00001171 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
1172 lphttpHdr->lpszValue = NULL;
1173 bSuccess = TRUE;
1174 }
1175 else
1176 {
1177 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1178 if (lpsztmp)
1179 {
1180 lphttpHdr->lpszValue = lpsztmp;
1181 strcpy(lpsztmp, value);
1182 bSuccess = TRUE;
1183 }
1184 else
1185 {
1186 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1187 }
1188 }
1189 }
1190 else if (dwModifier & COALESCEFLASG)
1191 {
1192 LPSTR lpsztmp;
1193 CHAR ch = 0;
1194 INT len = 0;
1195 INT origlen = strlen(lphttpHdr->lpszValue);
1196 INT valuelen = strlen(value);
1197
1198 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
1199 {
1200 ch = ',';
1201 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1202 }
1203 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1204 {
1205 ch = ';';
1206 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1207 }
1208
1209 len = origlen + valuelen + (ch > 0) ? 1 : 0;
1210
1211 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1212 if (lpsztmp)
1213 {
Vincent Béron9a624912002-05-31 23:06:46 +00001214 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
Ulrich Czekallac2757242000-06-11 20:04:44 +00001215 if (ch > 0)
1216 {
1217 lphttpHdr->lpszValue[origlen] = ch;
1218 origlen++;
1219 }
1220
1221 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
1222 lphttpHdr->lpszValue[len] = '\0';
1223 bSuccess = TRUE;
1224 }
1225 else
1226 {
1227 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1228 }
1229 }
1230 }
1231
1232 return bSuccess;
1233}
1234
1235
1236/***********************************************************************
1237 * HTTP_CloseConnection (internal)
1238 *
1239 * Close socket connection
1240 *
1241 */
1242VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
1243{
Francois Gougeta0f98f12001-08-24 19:13:36 +00001244 if (lpwhr->nSocketFD != -1)
Ulrich Czekallac2757242000-06-11 20:04:44 +00001245 {
1246 close(lpwhr->nSocketFD);
Francois Gougeta0f98f12001-08-24 19:13:36 +00001247 lpwhr->nSocketFD = -1;
Ulrich Czekallac2757242000-06-11 20:04:44 +00001248 }
1249}
1250
1251
1252/***********************************************************************
1253 * HTTP_CloseHTTPRequestHandle (internal)
1254 *
1255 * Deallocate request handle
1256 *
1257 */
1258void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
1259{
1260 int i;
1261
1262 TRACE("\n");
1263
Francois Gougeta0f98f12001-08-24 19:13:36 +00001264 if (lpwhr->nSocketFD != -1)
Ulrich Czekallac2757242000-06-11 20:04:44 +00001265 HTTP_CloseConnection(lpwhr);
1266
1267 if (lpwhr->lpszPath)
1268 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1269 if (lpwhr->lpszVerb)
1270 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1271 if (lpwhr->lpszHostName)
1272 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1273
1274 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1275 {
1276 if (lpwhr->StdHeaders[i].lpszField)
1277 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
1278 if (lpwhr->StdHeaders[i].lpszValue)
1279 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
1280 }
1281
1282 for (i = 0; i < lpwhr->nCustHeaders; i++)
1283 {
1284 if (lpwhr->pCustHeaders[i].lpszField)
1285 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1286 if (lpwhr->pCustHeaders[i].lpszValue)
1287 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1288 }
1289
1290 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1291 HeapFree(GetProcessHeap(), 0, lpwhr);
1292}
1293
1294
1295/***********************************************************************
1296 * HTTP_CloseHTTPSessionHandle (internal)
1297 *
1298 * Deallocate session handle
1299 *
1300 */
1301void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
1302{
1303 TRACE("\n");
1304
1305 if (lpwhs->lpszServerName)
1306 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1307 if (lpwhs->lpszUserName)
1308 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1309 HeapFree(GetProcessHeap(), 0, lpwhs);
1310}
1311
1312
1313/***********************************************************************
1314 * HTTP_GetCustomHeaderIndex (internal)
1315 *
1316 * Return index of custom header from header array
1317 *
1318 */
1319INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
1320{
1321 INT index;
1322
1323 TRACE("%s\n", lpszField);
1324
1325 for (index = 0; index < lpwhr->nCustHeaders; index++)
1326 {
Alexandre Julliard5ab9d862000-08-09 22:35:05 +00001327 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
Ulrich Czekallac2757242000-06-11 20:04:44 +00001328 break;
1329
1330 }
1331
1332 if (index >= lpwhr->nCustHeaders)
1333 index = -1;
1334
1335 TRACE("Return: %d\n", index);
1336 return index;
1337}
1338
1339
1340/***********************************************************************
1341 * HTTP_InsertCustomHeader (internal)
1342 *
1343 * Insert header into array
1344 *
1345 */
1346INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
1347{
1348 INT count;
1349 LPHTTPHEADERA lph = NULL;
1350
1351 TRACE("%s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
1352 count = lpwhr->nCustHeaders + 1;
1353 if (count > 1)
1354 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
1355 else
1356 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
1357
1358 if (NULL != lph)
1359 {
1360 lpwhr->pCustHeaders = lph;
Alexandre Julliard0e44f632000-11-16 00:28:52 +00001361 lpwhr->pCustHeaders[count-1].lpszField = HTTP_strdup(lpHdr->lpszField);
1362 lpwhr->pCustHeaders[count-1].lpszValue = HTTP_strdup(lpHdr->lpszValue);
Ulrich Czekallac2757242000-06-11 20:04:44 +00001363 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
1364 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
1365 lpwhr->nCustHeaders++;
1366 }
1367 else
1368 {
1369 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1370 count = 0;
1371 }
1372
1373 TRACE("%d <--\n", count-1);
1374 return count - 1;
1375}
1376
1377
1378/***********************************************************************
1379 * HTTP_DeleteCustomHeader (internal)
1380 *
1381 * Delete header from array
1382 *
1383 */
1384BOOL HTTP_DeleteCustomHeader(INT index)
1385{
1386 TRACE("\n");
1387 return FALSE;
1388}