2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_SOCKET_H
29 # include <sys/socket.h>
45 #define NO_SHLWAPI_STREAM
49 #include "wine/debug.h"
50 #include "wine/unicode.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
54 #define HTTPHEADER " HTTP/1.0"
55 #define HTTPHOSTHEADER "\r\nHost: "
56 #define MAXHOSTNAME 100
57 #define MAX_FIELD_VALUE_LEN 256
58 #define MAX_FIELD_LEN 256
61 #define HTTP_REFERER "Referer"
62 #define HTTP_ACCEPT "Accept"
63 #define HTTP_USERAGENT "User-Agent"
65 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
66 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
67 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
68 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
69 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
70 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
71 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
74 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
);
75 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr
,
76 void *Buffer
, int BytesToWrite
);
77 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr
,
78 void *Buffer
, int BytesToRead
);
79 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
);
80 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
);
81 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
);
82 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
);
83 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
);
84 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
);
85 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
);
87 inline static LPSTR
HTTP_strdup( LPCSTR str
)
89 LPSTR ret
= HeapAlloc( GetProcessHeap(), 0, strlen(str
) + 1 );
90 if (ret
) strcpy( ret
, str
);
94 /***********************************************************************
95 * HttpAddRequestHeadersA (WININET.@)
97 * Adds one or more HTTP header to the request handler
104 BOOL WINAPI
HttpAddRequestHeadersA(HINTERNET hHttpRequest
,
105 LPCSTR lpszHeader
, DWORD dwHeaderLength
, DWORD dwModifier
)
110 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
111 BOOL bSuccess
= FALSE
;
112 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
116 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
118 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
122 buffer
= HTTP_strdup(lpszHeader
);
129 while (*lpszEnd
!= '\0')
131 if (*lpszEnd
== '\r' && *(lpszEnd
+ 1) == '\n')
136 if (*lpszEnd
== '\0')
141 if (HTTP_InterpretHttpHeader(lpszStart
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
142 bSuccess
= HTTP_ProcessHeader(lpwhr
, field
, value
, dwModifier
| HTTP_ADDHDR_FLAG_REQ
);
144 lpszStart
= lpszEnd
+ 2; /* Jump over \0\n */
148 HeapFree(GetProcessHeap(), 0, buffer
);
152 /***********************************************************************
153 * HttpEndRequestA (WININET.@)
155 * Ends an HTTP request that was started by HttpSendRequestEx
162 BOOL WINAPI
HttpEndRequestA(HINTERNET hRequest
, LPINTERNET_BUFFERSA lpBuffersOut
,
163 DWORD dwFlags
, DWORD dwContext
)
169 /***********************************************************************
170 * HttpEndRequestW (WININET.@)
172 * Ends an HTTP request that was started by HttpSendRequestEx
179 BOOL WINAPI
HttpEndRequestW(HINTERNET hRequest
, LPINTERNET_BUFFERSW lpBuffersOut
,
180 DWORD dwFlags
, DWORD dwContext
)
186 /***********************************************************************
187 * HttpOpenRequestA (WININET.@)
189 * Open a HTTP request handle
192 * HINTERNET a HTTP request handle on success
196 HINTERNET WINAPI
HttpOpenRequestA(HINTERNET hHttpSession
,
197 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
198 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
199 DWORD dwFlags
, DWORD dwContext
)
201 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
202 LPWININETAPPINFOA hIC
= NULL
;
204 TRACE("(%s, %s, %s, %s, %ld, %ld)\n", lpszVerb
, lpszObjectName
, lpszVersion
, lpszReferrer
, dwFlags
, dwContext
);
205 if(lpszAcceptTypes
!=NULL
)
208 for(i
=0;lpszAcceptTypes
[i
]!=NULL
;i
++)
209 TRACE("\taccept type: %s\n",lpszAcceptTypes
[i
]);
212 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
214 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
217 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
220 * My tests seem to show that the windows version does not
221 * become asynchronous until after this point. And anyhow
222 * if this call was asynchronous then how would you get the
223 * necessary HINTERNET pointer returned by this function.
225 * I am leaving this here just in case I am wrong
227 * if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
231 WORKREQUEST workRequest
;
233 workRequest
.asyncall
= HTTPOPENREQUESTA
;
234 workRequest
.HFTPSESSION
= (DWORD
)hHttpSession
;
235 workRequest
.LPSZVERB
= (DWORD
)HTTP_strdup(lpszVerb
);
236 workRequest
.LPSZOBJECTNAME
= (DWORD
)HTTP_strdup(lpszObjectName
);
238 workRequest
.LPSZVERSION
= (DWORD
)HTTP_strdup(lpszVersion
);
240 workRequest
.LPSZVERSION
= 0;
242 workRequest
.LPSZREFERRER
= (DWORD
)HTTP_strdup(lpszReferrer
);
244 workRequest
.LPSZREFERRER
= 0;
245 workRequest
.LPSZACCEPTTYPES
= (DWORD
)lpszAcceptTypes
;
246 workRequest
.DWFLAGS
= dwFlags
;
247 workRequest
.DWCONTEXT
= dwContext
;
249 INTERNET_AsyncCall(&workRequest
);
254 return HTTP_HttpOpenRequestA(hHttpSession
, lpszVerb
, lpszObjectName
,
255 lpszVersion
, lpszReferrer
, lpszAcceptTypes
, dwFlags
, dwContext
);
259 /***********************************************************************
260 * HttpOpenRequestW (WININET.@)
262 * Open a HTTP request handle
265 * HINTERNET a HTTP request handle on success
269 HINTERNET WINAPI
HttpOpenRequestW(HINTERNET hHttpSession
,
270 LPCWSTR lpszVerb
, LPCWSTR lpszObjectName
, LPCWSTR lpszVersion
,
271 LPCWSTR lpszReferrer
, LPCWSTR
*lpszAcceptTypes
,
272 DWORD dwFlags
, DWORD dwContext
)
275 szObjectName
[INTERNET_MAX_PATH_LENGTH
];
276 TRACE("(%s, %s, %s, %s, %ld, %ld)\n", debugstr_w(lpszVerb
), debugstr_w(lpszObjectName
), debugstr_w(lpszVersion
), debugstr_w(lpszReferrer
), dwFlags
, dwContext
);
279 WideCharToMultiByte(CP_ACP
,0,lpszVerb
,-1,szVerb
,20,NULL
,NULL
);
282 if(lpszObjectName
!=NULL
)
283 WideCharToMultiByte(CP_ACP
,0,lpszObjectName
,-1,szObjectName
,INTERNET_MAX_PATH_LENGTH
,NULL
,NULL
);
286 TRACE("object name=%s\n",szObjectName
);
287 FIXME("lpszVersion, lpszReferrer and lpszAcceptTypes ignored\n");
288 return HttpOpenRequestA(hHttpSession
, szVerb
[0]?szVerb
:NULL
, szObjectName
, NULL
, NULL
, NULL
, dwFlags
, dwContext
);
291 /***********************************************************************
292 * HTTP_HttpOpenRequestA (internal)
294 * Open a HTTP request handle
297 * HINTERNET a HTTP request handle on success
301 HINTERNET WINAPI
HTTP_HttpOpenRequestA(HINTERNET hHttpSession
,
302 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
303 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
304 DWORD dwFlags
, DWORD dwContext
)
306 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
307 LPWININETAPPINFOA hIC
= NULL
;
308 LPWININETHTTPREQA lpwhr
;
312 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
314 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
318 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
320 lpwhr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPREQA
));
323 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
324 return (HINTERNET
) NULL
;
327 lpwhr
->hdr
.htype
= WH_HHTTPREQ
;
328 lpwhr
->hdr
.lpwhparent
= hHttpSession
;
329 lpwhr
->hdr
.dwFlags
= dwFlags
;
330 lpwhr
->hdr
.dwContext
= dwContext
;
331 lpwhr
->nSocketFD
= -1;
333 if (NULL
!= lpszObjectName
&& strlen(lpszObjectName
)) {
336 rc
= UrlEscapeA(lpszObjectName
, NULL
, &needed
, URL_ESCAPE_SPACES_ONLY
);
338 needed
= strlen(lpszObjectName
)+1;
339 lpwhr
->lpszPath
= HeapAlloc(GetProcessHeap(), 0, needed
);
340 rc
= UrlEscapeA(lpszObjectName
, lpwhr
->lpszPath
, &needed
,
341 URL_ESCAPE_SPACES_ONLY
);
344 ERR("Unable to escape string!(%s) (%ld)\n",lpszObjectName
,rc
);
345 strcpy(lpwhr
->lpszPath
,lpszObjectName
);
349 if (NULL
!= hIC
->lpszAgent
&& strlen(hIC
->lpszAgent
))
350 HTTP_ProcessHeader(lpwhr
, HTTP_USERAGENT
, hIC
->lpszAgent
, HTTP_ADDHDR_FLAG_REQ
|HTTP_ADDREQ_FLAG_REPLACE
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
);
352 if (NULL
!= lpszReferrer
&& strlen(lpszReferrer
))
353 HTTP_ProcessHeader(lpwhr
, HTTP_REFERER
, lpszReferrer
, HTTP_ADDHDR_FLAG_REQ
|HTTP_ADDREQ_FLAG_REPLACE
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
);
355 if(lpszAcceptTypes
!=NULL
)
358 for(i
=0;lpszAcceptTypes
[i
]!=NULL
;i
++)
359 HTTP_ProcessHeader(lpwhr
, HTTP_ACCEPT
, lpszAcceptTypes
[i
], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA
|HTTP_ADDHDR_FLAG_REQ
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
);
362 if (NULL
== lpszVerb
)
363 lpwhr
->lpszVerb
= HTTP_strdup("GET");
364 else if (strlen(lpszVerb
))
365 lpwhr
->lpszVerb
= HTTP_strdup(lpszVerb
);
367 if (NULL
!= lpszReferrer
)
369 char buf
[MAXHOSTNAME
];
370 URL_COMPONENTSA UrlComponents
;
372 UrlComponents
.lpszExtraInfo
= NULL
;
373 UrlComponents
.lpszPassword
= NULL
;
374 UrlComponents
.lpszScheme
= NULL
;
375 UrlComponents
.lpszUrlPath
= NULL
;
376 UrlComponents
.lpszUserName
= NULL
;
377 UrlComponents
.lpszHostName
= buf
;
378 UrlComponents
.dwHostNameLength
= MAXHOSTNAME
;
380 InternetCrackUrlA(lpszReferrer
, 0, 0, &UrlComponents
);
381 if (strlen(UrlComponents
.lpszHostName
))
382 lpwhr
->lpszHostName
= HTTP_strdup(UrlComponents
.lpszHostName
);
384 lpwhr
->lpszHostName
= HTTP_strdup(lpwhs
->lpszServerName
);
387 if (hIC
->lpfnStatusCB
)
389 INTERNET_ASYNC_RESULT iar
;
391 iar
.dwResult
= (DWORD
)lpwhr
;
392 iar
.dwError
= ERROR_SUCCESS
;
394 SendAsyncCallback(hIC
, hHttpSession
, dwContext
,
395 INTERNET_STATUS_HANDLE_CREATED
, &iar
,
396 sizeof(INTERNET_ASYNC_RESULT
));
400 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
404 * According to my tests. The name is not resolved until a request is Opened
406 SendAsyncCallback(hIC
, hHttpSession
, dwContext
,
407 INTERNET_STATUS_RESOLVING_NAME
,
408 lpwhs
->lpszServerName
,
409 strlen(lpwhs
->lpszServerName
)+1);
411 if (!GetAddress(lpwhs
->lpszServerName
, lpwhs
->nServerPort
,
412 &lpwhs
->phostent
, &lpwhs
->socketAddress
))
414 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
418 SendAsyncCallback(hIC
, hHttpSession
, lpwhr
->hdr
.dwContext
,
419 INTERNET_STATUS_NAME_RESOLVED
,
420 &(lpwhs
->socketAddress
),
421 sizeof(struct sockaddr_in
));
424 return (HINTERNET
) lpwhr
;
428 /***********************************************************************
429 * HttpQueryInfoA (WININET.@)
431 * Queries for information about an HTTP request
438 BOOL WINAPI
HttpQueryInfoA(HINTERNET hHttpRequest
, DWORD dwInfoLevel
,
439 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
441 LPHTTPHEADERA lphttpHdr
= NULL
;
442 BOOL bSuccess
= FALSE
;
443 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
445 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel
, dwInfoLevel
);
447 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
449 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
453 /* Find requested header structure */
454 if ((dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
) == HTTP_QUERY_CUSTOM
)
456 INT index
= HTTP_GetCustomHeaderIndex(lpwhr
, (LPSTR
)lpBuffer
);
461 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
465 INT index
= dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
;
467 if (index
== HTTP_QUERY_RAW_HEADERS_CRLF
|| index
== HTTP_QUERY_RAW_HEADERS
)
469 INT i
, delim
, size
= 0, cnt
= 0;
471 delim
= index
== HTTP_QUERY_RAW_HEADERS_CRLF
? 2 : 1;
473 /* Calculate length of custom reuqest headers */
474 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
476 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->pCustHeaders
[i
].lpszField
&&
477 lpwhr
->pCustHeaders
[i
].lpszValue
)
479 size
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
480 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + delim
+ 2;
484 /* Calculate the length of stadard request headers */
485 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
487 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->StdHeaders
[i
].lpszField
&&
488 lpwhr
->StdHeaders
[i
].lpszValue
)
490 size
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
491 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + delim
+ 2;
496 if (size
+ 1 > *lpdwBufferLength
)
498 *lpdwBufferLength
= size
+ 1;
499 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
503 /* Append standard request heades */
504 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
506 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
507 lpwhr
->StdHeaders
[i
].lpszField
&&
508 lpwhr
->StdHeaders
[i
].lpszValue
)
510 cnt
+= sprintf((char*)lpBuffer
+ cnt
, "%s: %s%s", lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
,
511 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
515 /* Append custom request heades */
516 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
518 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
519 lpwhr
->pCustHeaders
[i
].lpszField
&&
520 lpwhr
->pCustHeaders
[i
].lpszValue
)
522 cnt
+= sprintf((char*)lpBuffer
+ cnt
, "%s: %s%s",
523 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
,
524 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
528 strcpy((char*)lpBuffer
+ cnt
, index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "");
530 *lpdwBufferLength
= cnt
+ delim
;
534 else if (index
>= 0 && index
<= HTTP_QUERY_MAX
&& lpwhr
->StdHeaders
[index
].lpszValue
)
536 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
542 /* Ensure header satisifies requested attributes */
543 if ((dwInfoLevel
& HTTP_QUERY_FLAG_REQUEST_HEADERS
) &&
544 (~lphttpHdr
->wFlags
& HDR_ISREQUEST
))
547 /* coalesce value to reuqested type */
548 if (dwInfoLevel
& HTTP_QUERY_FLAG_NUMBER
)
550 *(int *)lpBuffer
= atoi(lphttpHdr
->lpszValue
);
553 else if (dwInfoLevel
& HTTP_QUERY_FLAG_SYSTEMTIME
)
559 tmpTime
= ConvertTimeString(lphttpHdr
->lpszValue
);
561 tmpTM
= *gmtime(&tmpTime
);
562 STHook
= (SYSTEMTIME
*) lpBuffer
;
566 STHook
->wDay
= tmpTM
.tm_mday
;
567 STHook
->wHour
= tmpTM
.tm_hour
;
568 STHook
->wMilliseconds
= 0;
569 STHook
->wMinute
= tmpTM
.tm_min
;
570 STHook
->wDayOfWeek
= tmpTM
.tm_wday
;
571 STHook
->wMonth
= tmpTM
.tm_mon
+ 1;
572 STHook
->wSecond
= tmpTM
.tm_sec
;
573 STHook
->wYear
= tmpTM
.tm_year
;
577 else if (dwInfoLevel
& HTTP_QUERY_FLAG_COALESCE
)
579 if (*lpdwIndex
>= lphttpHdr
->wCount
)
581 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND
);
585 /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
591 INT len
= strlen(lphttpHdr
->lpszValue
);
593 if (len
+ 1 > *lpdwBufferLength
)
595 *lpdwBufferLength
= len
+ 1;
596 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
600 strncpy(lpBuffer
, lphttpHdr
->lpszValue
, len
);
601 ((char*)lpBuffer
)[len
]=0;
602 *lpdwBufferLength
= len
;
607 TRACE("%d <--\n", bSuccess
);
611 /***********************************************************************
612 * HttpQueryInfoW (WININET.@)
614 * Queries for information about an HTTP request
621 BOOL WINAPI
HttpQueryInfoW(HINTERNET hHttpRequest
, DWORD dwInfoLevel
,
622 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
625 DWORD charLen
=*lpdwBufferLength
;
626 char* tempBuffer
=HeapAlloc(GetProcessHeap(), 0, charLen
);
627 result
=HttpQueryInfoA(hHttpRequest
, dwInfoLevel
, tempBuffer
, &charLen
, lpdwIndex
);
628 if((dwInfoLevel
& HTTP_QUERY_FLAG_NUMBER
) ||
629 (dwInfoLevel
& HTTP_QUERY_FLAG_SYSTEMTIME
))
631 memcpy(lpBuffer
,tempBuffer
,charLen
);
635 int nChars
=MultiByteToWideChar(CP_ACP
,0, tempBuffer
,charLen
,lpBuffer
,*lpdwBufferLength
);
636 *lpdwBufferLength
=nChars
;
638 HeapFree(GetProcessHeap(), 0, tempBuffer
);
642 /***********************************************************************
643 * HttpSendRequestExA (WININET.@)
645 * Sends the specified request to the HTTP server and allows chunked
648 BOOL WINAPI
HttpSendRequestExA(HINTERNET hRequest
,
649 LPINTERNET_BUFFERSA lpBuffersIn
,
650 LPINTERNET_BUFFERSA lpBuffersOut
,
651 DWORD dwFlags
, DWORD dwContext
)
653 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest
, lpBuffersIn
,
654 lpBuffersOut
, dwFlags
, dwContext
);
658 /***********************************************************************
659 * HttpSendRequestA (WININET.@)
661 * Sends the specified request to the HTTP server
668 BOOL WINAPI
HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
669 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
671 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
672 LPWININETHTTPSESSIONA lpwhs
= NULL
;
673 LPWININETAPPINFOA hIC
= NULL
;
675 TRACE("0x%08lx\n", (unsigned long)hHttpRequest
);
677 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
679 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
683 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
684 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
686 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
690 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
691 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
693 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
697 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
699 WORKREQUEST workRequest
;
701 workRequest
.asyncall
= HTTPSENDREQUESTA
;
702 workRequest
.HFTPSESSION
= (DWORD
)hHttpRequest
;
704 workRequest
.LPSZHEADER
= (DWORD
)HTTP_strdup(lpszHeaders
);
706 workRequest
.LPSZHEADER
= 0;
707 workRequest
.DWHEADERLENGTH
= dwHeaderLength
;
708 workRequest
.LPOPTIONAL
= (DWORD
)lpOptional
;
709 workRequest
.DWOPTIONALLENGTH
= dwOptionalLength
;
711 INTERNET_AsyncCall(&workRequest
);
713 * This is from windows.
715 SetLastError(ERROR_IO_PENDING
);
720 return HTTP_HttpSendRequestA(hHttpRequest
, lpszHeaders
,
721 dwHeaderLength
, lpOptional
, dwOptionalLength
);
725 /***********************************************************************
726 * HttpSendRequestW (WININET.@)
728 * Sends the specified request to the HTTP server
735 BOOL WINAPI
HttpSendRequestW(HINTERNET hHttpRequest
, LPCWSTR lpszHeaders
,
736 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
739 char* szHeaders
=NULL
;
740 DWORD nLen
=dwHeaderLength
;
741 if(lpszHeaders
!=NULL
)
744 nLen
=strlenW(lpszHeaders
);
745 szHeaders
=(char*)malloc(nLen
+1);
746 WideCharToMultiByte(CP_ACP
,0,lpszHeaders
,nLen
,szHeaders
,nLen
,NULL
,NULL
);
748 result
=HttpSendRequestA(hHttpRequest
, szHeaders
, dwHeaderLength
, lpOptional
, dwOptionalLength
);
754 /***********************************************************************
755 * HTTP_HandleRedirect (internal)
757 static BOOL
HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr
, LPCSTR lpszUrl
, LPCSTR lpszHeaders
,
758 DWORD dwHeaderLength
, LPVOID lpOptional
, DWORD dwOptionalLength
)
760 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
761 LPWININETAPPINFOA hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
765 /* if it's an absolute path, keep the same session info */
766 strcpy(path
,lpszUrl
);
770 URL_COMPONENTSA urlComponents
;
771 char protocol
[32], hostName
[MAXHOSTNAME
], userName
[1024];
772 char password
[1024], extra
[1024];
773 urlComponents
.dwStructSize
= sizeof(URL_COMPONENTSA
);
774 urlComponents
.lpszScheme
= protocol
;
775 urlComponents
.dwSchemeLength
= 32;
776 urlComponents
.lpszHostName
= hostName
;
777 urlComponents
.dwHostNameLength
= MAXHOSTNAME
;
778 urlComponents
.lpszUserName
= userName
;
779 urlComponents
.dwUserNameLength
= 1024;
780 urlComponents
.lpszPassword
= password
;
781 urlComponents
.dwPasswordLength
= 1024;
782 urlComponents
.lpszUrlPath
= path
;
783 urlComponents
.dwUrlPathLength
= 2048;
784 urlComponents
.lpszExtraInfo
= extra
;
785 urlComponents
.dwExtraInfoLength
= 1024;
786 if(!InternetCrackUrlA(lpszUrl
, strlen(lpszUrl
), 0, &urlComponents
))
789 if (urlComponents
.nPort
== INTERNET_INVALID_PORT_NUMBER
)
790 urlComponents
.nPort
= INTERNET_DEFAULT_HTTP_PORT
;
792 /* consider the current host as the referef */
793 if (NULL
!= lpwhs
->lpszServerName
&& strlen(lpwhs
->lpszServerName
))
794 HTTP_ProcessHeader(lpwhr
, HTTP_REFERER
, lpwhs
->lpszServerName
, HTTP_ADDHDR_FLAG_REQ
|HTTP_ADDREQ_FLAG_REPLACE
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
);
796 if (NULL
!= lpwhs
->lpszServerName
)
797 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
798 lpwhs
->lpszServerName
= HTTP_strdup(hostName
);
799 if (NULL
!= lpwhs
->lpszUserName
)
800 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszUserName
);
801 lpwhs
->lpszUserName
= HTTP_strdup(userName
);
802 lpwhs
->nServerPort
= urlComponents
.nPort
;
804 if (NULL
!= lpwhr
->lpszHostName
)
805 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszHostName
);
806 lpwhr
->lpszHostName
=HTTP_strdup(hostName
);
808 SendAsyncCallback(hIC
, lpwhs
, lpwhr
->hdr
.dwContext
,
809 INTERNET_STATUS_RESOLVING_NAME
,
810 lpwhs
->lpszServerName
,
811 strlen(lpwhs
->lpszServerName
)+1);
813 if (!GetAddress(lpwhs
->lpszServerName
, lpwhs
->nServerPort
,
814 &lpwhs
->phostent
, &lpwhs
->socketAddress
))
816 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
820 SendAsyncCallback(hIC
, lpwhs
, lpwhr
->hdr
.dwContext
,
821 INTERNET_STATUS_NAME_RESOLVED
,
822 &(lpwhs
->socketAddress
),
823 sizeof(struct sockaddr_in
));
828 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszPath
);
829 lpwhr
->lpszPath
=NULL
;
834 rc
= UrlEscapeA(path
, NULL
, &needed
, URL_ESCAPE_SPACES_ONLY
);
836 needed
= strlen(path
)+1;
837 lpwhr
->lpszPath
= HeapAlloc(GetProcessHeap(), 0, needed
);
838 rc
= UrlEscapeA(path
, lpwhr
->lpszPath
, &needed
,
839 URL_ESCAPE_SPACES_ONLY
);
842 ERR("Unable to escape string!(%s) (%ld)\n",path
,rc
);
843 strcpy(lpwhr
->lpszPath
,path
);
847 return HttpSendRequestA((HINTERNET
)lpwhr
, lpszHeaders
, dwHeaderLength
, lpOptional
, dwOptionalLength
);
850 /***********************************************************************
851 * HTTP_HttpSendRequestA (internal)
853 * Sends the specified request to the HTTP server
860 BOOL WINAPI
HTTP_HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
861 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
865 BOOL bSuccess
= FALSE
;
866 LPSTR requestString
= NULL
;
867 INT requestStringLen
;
869 INT headerLength
= 0;
870 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
871 LPWININETHTTPSESSIONA lpwhs
= NULL
;
872 LPWININETAPPINFOA hIC
= NULL
;
874 TRACE("--> 0x%08lx\n", (ULONG
)hHttpRequest
);
876 /* Verify our tree of internet handles */
877 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
879 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
883 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
884 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
886 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
890 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
891 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
893 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
897 /* Clear any error information */
898 INTERNET_SetLastError(0);
901 /* We must have a verb */
902 if (NULL
== lpwhr
->lpszVerb
)
907 /* If we don't have a path we set it to root */
908 if (NULL
== lpwhr
->lpszPath
)
909 lpwhr
->lpszPath
= HTTP_strdup("/");
911 if(lpwhr
->lpszPath
[0] != '/') /* not an absolute path ?? --> fix it !! */
913 char *fixurl
= HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr
->lpszPath
) + 2);
915 strcpy(fixurl
+ 1, lpwhr
->lpszPath
);
916 HeapFree( GetProcessHeap(), 0, lpwhr
->lpszPath
);
917 lpwhr
->lpszPath
= fixurl
;
920 /* Calculate length of request string */
922 strlen(lpwhr
->lpszVerb
) +
923 strlen(lpwhr
->lpszPath
) +
924 (lpwhr
->lpszHostName
? (strlen(HTTPHOSTHEADER
) + strlen(lpwhr
->lpszHostName
)) : 0) +
928 /* Add length of passed headers */
931 headerLength
= -1 == dwHeaderLength
? strlen(lpszHeaders
) : dwHeaderLength
;
932 requestStringLen
+= headerLength
+ 2; /* \r\n */
935 /* Calculate length of custom request headers */
936 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
938 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
940 requestStringLen
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
941 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + 4; /*: \r\n */
945 /* Calculate the length of standard request headers */
946 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
948 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
950 requestStringLen
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
951 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + 4; /*: \r\n */
955 /* Allocate string to hold entire request */
956 requestString
= HeapAlloc(GetProcessHeap(), 0, requestStringLen
+ 1);
957 if (NULL
== requestString
)
959 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
963 /* Build request string */
964 cnt
= sprintf(requestString
, "%s %s%s%s",
967 lpwhr
->lpszHostName
? (HTTPHEADER HTTPHOSTHEADER
) : HTTPHEADER
,
968 lpwhr
->lpszHostName
? lpwhr
->lpszHostName
: "");
970 /* Append standard request headers */
971 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
973 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
975 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
976 lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
);
977 TRACE("Adding header %s (%s)\n",lpwhr
->StdHeaders
[i
].lpszField
,lpwhr
->StdHeaders
[i
].lpszValue
);
981 /* Append custom request heades */
982 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
984 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
986 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
987 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
);
988 TRACE("Adding custom header %s (%s)\n",lpwhr
->pCustHeaders
[i
].lpszField
,lpwhr
->pCustHeaders
[i
].lpszValue
);
992 /* Append passed request headers */
995 strcpy(requestString
+ cnt
, "\r\n");
997 strcpy(requestString
+ cnt
, lpszHeaders
);
1001 /* Set termination string for request */
1002 strcpy(requestString
+ cnt
, "\r\n\r\n");
1004 TRACE("(%s) len(%d)\n", requestString
, requestStringLen
);
1005 /* Send the request and store the results */
1006 if (!HTTP_OpenConnection(lpwhr
))
1009 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
1010 INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1012 cnt
= send(lpwhr
->nSocketFD
, requestString
, requestStringLen
, 0);
1014 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
1015 INTERNET_STATUS_REQUEST_SENT
,
1016 &requestStringLen
,sizeof(DWORD
));
1018 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
1019 INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
1024 responseLen
= HTTP_GetResponseHeaders(lpwhr
);
1028 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
1029 INTERNET_STATUS_RESPONSE_RECEIVED
, &responseLen
,
1035 HeapFree(GetProcessHeap(), 0, requestString
);
1037 /* TODO: send notification for P3P header */
1039 if(!(hIC
->hdr
.dwFlags
& INTERNET_FLAG_NO_AUTO_REDIRECT
) && bSuccess
)
1041 DWORD dwCode
,dwCodeLength
=sizeof(DWORD
),dwIndex
=0;
1042 if(HttpQueryInfoA(hHttpRequest
,HTTP_QUERY_FLAG_NUMBER
|HTTP_QUERY_STATUS_CODE
,&dwCode
,&dwCodeLength
,&dwIndex
) &&
1043 (dwCode
==302 || dwCode
==301))
1045 char szNewLocation
[2048];
1046 DWORD dwBufferSize
=2048;
1048 if(HttpQueryInfoA(hHttpRequest
,HTTP_QUERY_LOCATION
,szNewLocation
,&dwBufferSize
,&dwIndex
))
1050 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
1051 INTERNET_STATUS_REDIRECT
, szNewLocation
,
1053 return HTTP_HandleRedirect(lpwhr
, szNewLocation
, lpszHeaders
,
1054 dwHeaderLength
, lpOptional
, dwOptionalLength
);
1059 if (hIC
->lpfnStatusCB
)
1061 INTERNET_ASYNC_RESULT iar
;
1063 iar
.dwResult
= (DWORD
)bSuccess
;
1064 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1066 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
1067 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
1068 sizeof(INTERNET_ASYNC_RESULT
));
1076 /***********************************************************************
1077 * HTTP_Connect (internal)
1079 * Create http session handle
1082 * HINTERNET a session handle on success
1086 HINTERNET
HTTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
1087 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
1088 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
1090 BOOL bSuccess
= FALSE
;
1091 LPWININETAPPINFOA hIC
= NULL
;
1092 LPWININETHTTPSESSIONA lpwhs
= NULL
;
1096 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
1099 hIC
= (LPWININETAPPINFOA
) hInternet
;
1100 hIC
->hdr
.dwContext
= dwContext
;
1102 lpwhs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPSESSIONA
));
1105 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1110 * According to my tests. The name is not resolved until a request is sent
1113 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1114 nServerPort
= INTERNET_DEFAULT_HTTP_PORT
;
1116 lpwhs
->hdr
.htype
= WH_HHTTPSESSION
;
1117 lpwhs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
1118 lpwhs
->hdr
.dwFlags
= dwFlags
;
1119 lpwhs
->hdr
.dwContext
= dwContext
;
1120 if (NULL
!= lpszServerName
)
1121 lpwhs
->lpszServerName
= HTTP_strdup(lpszServerName
);
1122 if (NULL
!= lpszUserName
)
1123 lpwhs
->lpszUserName
= HTTP_strdup(lpszUserName
);
1124 lpwhs
->nServerPort
= nServerPort
;
1126 if (hIC
->lpfnStatusCB
)
1128 INTERNET_ASYNC_RESULT iar
;
1130 iar
.dwResult
= (DWORD
)lpwhs
;
1131 iar
.dwError
= ERROR_SUCCESS
;
1133 SendAsyncCallback(hIC
, hInternet
, dwContext
,
1134 INTERNET_STATUS_HANDLE_CREATED
, &iar
,
1135 sizeof(INTERNET_ASYNC_RESULT
));
1141 if (!bSuccess
&& lpwhs
)
1143 HeapFree(GetProcessHeap(), 0, lpwhs
);
1148 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1153 return (HINTERNET
)lpwhs
;
1157 /***********************************************************************
1158 * HTTP_OpenConnection (internal)
1160 * Connect to a web server
1167 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
)
1169 BOOL bSuccess
= FALSE
;
1171 LPWININETHTTPSESSIONA lpwhs
;
1172 LPWININETAPPINFOA hIC
= NULL
;
1177 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
1179 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1183 lpwhs
= (LPWININETHTTPSESSIONA
)lpwhr
->hdr
.lpwhparent
;
1185 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
1186 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
1187 INTERNET_STATUS_CONNECTING_TO_SERVER
,
1188 &(lpwhs
->socketAddress
),
1189 sizeof(struct sockaddr_in
));
1191 lpwhr
->nSocketFD
= socket(lpwhs
->phostent
->h_addrtype
,SOCK_STREAM
,0);
1192 if (lpwhr
->nSocketFD
== -1)
1194 WARN("Socket creation failed\n");
1198 result
= connect(lpwhr
->nSocketFD
, (struct sockaddr
*)&lpwhs
->socketAddress
,
1199 sizeof(lpwhs
->socketAddress
));
1203 WARN("Unable to connect to host (%s)\n", strerror(errno
));
1207 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
1208 INTERNET_STATUS_CONNECTED_TO_SERVER
,
1209 &(lpwhs
->socketAddress
),
1210 sizeof(struct sockaddr_in
));
1215 TRACE("%d <--\n", bSuccess
);
1220 /***********************************************************************
1221 * HTTP_GetResponseHeaders (internal)
1223 * Read server response
1230 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
)
1233 CHAR buffer
[MAX_REPLY_LEN
];
1234 DWORD buflen
= MAX_REPLY_LEN
;
1235 BOOL bSuccess
= FALSE
;
1237 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
1241 if (lpwhr
->nSocketFD
== -1)
1245 * HACK peek at the buffer
1247 rc
= recv(lpwhr
->nSocketFD
,buffer
,buflen
,MSG_PEEK
);
1250 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1252 buflen
= MAX_REPLY_LEN
;
1253 if (!INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
1256 if (strncmp(buffer
, "HTTP", 4) != 0)
1260 HTTP_ProcessHeader(lpwhr
, "Status", buffer
+9, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
1262 /* Parse each response line */
1265 buflen
= MAX_REPLY_LEN
;
1266 if (INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
1268 if (!HTTP_InterpretHttpHeader(buffer
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
1271 HTTP_ProcessHeader(lpwhr
, field
, value
, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
1293 /***********************************************************************
1294 * HTTP_InterpretHttpHeader (internal)
1296 * Parse server response
1303 INT
stripSpaces(LPCSTR lpszSrc
, LPSTR lpszStart
, INT
*len
)
1310 while (*lpszSrc
== ' ' && *lpszSrc
!= '\0')
1314 while(*lpsztmp
!= '\0')
1316 if (*lpsztmp
!= ' ')
1317 srclen
= lpsztmp
- lpszSrc
+ 1;
1322 *len
= min(*len
, srclen
);
1323 strncpy(lpszStart
, lpszSrc
, *len
);
1324 lpszStart
[*len
] = '\0';
1330 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
)
1333 BOOL bSuccess
= FALSE
;
1340 pd
= strchr(buffer
, ':');
1344 if (stripSpaces(buffer
, field
, &fieldlen
) > 0)
1346 if (stripSpaces(pd
+1, value
, &valuelen
) > 0)
1351 TRACE("%d: field(%s) Value(%s)\n", bSuccess
, field
, value
);
1356 /***********************************************************************
1357 * HTTP_GetStdHeaderIndex (internal)
1359 * Lookup field index in standard http header array
1361 * FIXME: This should be stuffed into a hash table
1363 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
)
1367 if (!strcasecmp(lpszField
, "Content-Length"))
1368 index
= HTTP_QUERY_CONTENT_LENGTH
;
1369 else if (!strcasecmp(lpszField
,"Status"))
1370 index
= HTTP_QUERY_STATUS_CODE
;
1371 else if (!strcasecmp(lpszField
,"Content-Type"))
1372 index
= HTTP_QUERY_CONTENT_TYPE
;
1373 else if (!strcasecmp(lpszField
,"Last-Modified"))
1374 index
= HTTP_QUERY_LAST_MODIFIED
;
1375 else if (!strcasecmp(lpszField
,"Location"))
1376 index
= HTTP_QUERY_LOCATION
;
1377 else if (!strcasecmp(lpszField
,"Accept"))
1378 index
= HTTP_QUERY_ACCEPT
;
1379 else if (!strcasecmp(lpszField
,"Referer"))
1380 index
= HTTP_QUERY_REFERER
;
1381 else if (!strcasecmp(lpszField
,"Content-Transfer-Encoding"))
1382 index
= HTTP_QUERY_CONTENT_TRANSFER_ENCODING
;
1383 else if (!strcasecmp(lpszField
,"Date"))
1384 index
= HTTP_QUERY_DATE
;
1385 else if (!strcasecmp(lpszField
,"Server"))
1386 index
= HTTP_QUERY_SERVER
;
1387 else if (!strcasecmp(lpszField
,"Connection"))
1388 index
= HTTP_QUERY_CONNECTION
;
1389 else if (!strcasecmp(lpszField
,"ETag"))
1390 index
= HTTP_QUERY_ETAG
;
1391 else if (!strcasecmp(lpszField
,"Accept-Ranges"))
1392 index
= HTTP_QUERY_ACCEPT_RANGES
;
1393 else if (!strcasecmp(lpszField
,"Expires"))
1394 index
= HTTP_QUERY_EXPIRES
;
1395 else if (!strcasecmp(lpszField
,"Mime-Version"))
1396 index
= HTTP_QUERY_MIME_VERSION
;
1397 else if (!strcasecmp(lpszField
,"Pragma"))
1398 index
= HTTP_QUERY_PRAGMA
;
1399 else if (!strcasecmp(lpszField
,"Cache-Control"))
1400 index
= HTTP_QUERY_CACHE_CONTROL
;
1401 else if (!strcasecmp(lpszField
,"Content-Length"))
1402 index
= HTTP_QUERY_CONTENT_LENGTH
;
1403 else if (!strcasecmp(lpszField
,"User-Agent"))
1404 index
= HTTP_QUERY_USER_AGENT
;
1407 TRACE("Couldn't find %s in standard header table\n", lpszField
);
1414 /***********************************************************************
1415 * HTTP_ProcessHeader (internal)
1417 * Stuff header into header tables according to <dwModifier>
1421 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1423 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
)
1425 LPHTTPHEADERA lphttpHdr
= NULL
;
1426 BOOL bSuccess
= FALSE
;
1429 TRACE("--> %s: %s - 0x%08x\n", field
, value
, (unsigned int)dwModifier
);
1431 /* Adjust modifier flags */
1432 if (dwModifier
& COALESCEFLASG
)
1433 dwModifier
|= HTTP_ADDHDR_FLAG_ADD
;
1435 /* Try to get index into standard header array */
1436 index
= HTTP_GetStdHeaderIndex(field
);
1439 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
1441 else /* Find or create new custom header */
1443 index
= HTTP_GetCustomHeaderIndex(lpwhr
, field
);
1446 if (dwModifier
& HTTP_ADDHDR_FLAG_ADD_IF_NEW
)
1450 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
1456 hdr
.lpszField
= (LPSTR
)field
;
1457 hdr
.lpszValue
= (LPSTR
)value
;
1458 hdr
.wFlags
= hdr
.wCount
= 0;
1460 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1461 hdr
.wFlags
|= HDR_ISREQUEST
;
1463 index
= HTTP_InsertCustomHeader(lpwhr
, &hdr
);
1468 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1469 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1471 lphttpHdr
->wFlags
&= ~HDR_ISREQUEST
;
1473 if (!lphttpHdr
->lpszValue
&& (dwModifier
& (HTTP_ADDHDR_FLAG_ADD
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
)))
1477 if (!lpwhr
->StdHeaders
[index
].lpszField
)
1479 lphttpHdr
->lpszField
= HTTP_strdup(field
);
1481 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1482 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1485 slen
= strlen(value
) + 1;
1486 lphttpHdr
->lpszValue
= HeapAlloc(GetProcessHeap(), 0, slen
);
1487 if (lphttpHdr
->lpszValue
)
1489 memcpy(lphttpHdr
->lpszValue
, value
, slen
);
1494 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1497 else if (lphttpHdr
->lpszValue
)
1499 if (dwModifier
& HTTP_ADDHDR_FLAG_REPLACE
)
1504 len
= strlen(value
);
1508 /* if custom header delete from array */
1509 HeapFree(GetProcessHeap(), 0, lphttpHdr
->lpszValue
);
1510 lphttpHdr
->lpszValue
= NULL
;
1515 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1518 lphttpHdr
->lpszValue
= lpsztmp
;
1519 strcpy(lpsztmp
, value
);
1524 WARN("HeapReAlloc (%d bytes) failed\n",len
+1);
1525 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1529 else if (dwModifier
& COALESCEFLASG
)
1534 INT origlen
= strlen(lphttpHdr
->lpszValue
);
1535 INT valuelen
= strlen(value
);
1537 if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA
)
1540 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1542 else if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON
)
1545 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1548 len
= origlen
+ valuelen
+ ((ch
> 0) ? 1 : 0);
1550 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1553 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1556 lphttpHdr
->lpszValue
[origlen
] = ch
;
1560 memcpy(&lphttpHdr
->lpszValue
[origlen
], value
, valuelen
);
1561 lphttpHdr
->lpszValue
[len
] = '\0';
1566 WARN("HeapReAlloc (%d bytes) failed\n",len
+1);
1567 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1571 TRACE("<-- %d\n",bSuccess
);
1576 /***********************************************************************
1577 * HTTP_CloseConnection (internal)
1579 * Close socket connection
1582 VOID
HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
)
1586 LPWININETHTTPSESSIONA lpwhs
= NULL
;
1587 LPWININETAPPINFOA hIC
= NULL
;
1589 TRACE("%p\n",lpwhr
);
1591 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
1592 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
1594 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
1595 INTERNET_STATUS_CLOSING_CONNECTION
, 0, 0);
1597 if (lpwhr
->nSocketFD
!= -1)
1599 close(lpwhr
->nSocketFD
);
1600 lpwhr
->nSocketFD
= -1;
1603 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
1604 INTERNET_STATUS_CONNECTION_CLOSED
, 0, 0);
1608 /***********************************************************************
1609 * HTTP_CloseHTTPRequestHandle (internal)
1611 * Deallocate request handle
1614 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr
)
1617 LPWININETHTTPSESSIONA lpwhs
= NULL
;
1618 LPWININETAPPINFOA hIC
= NULL
;
1622 if (lpwhr
->nSocketFD
!= -1)
1623 HTTP_CloseConnection(lpwhr
);
1625 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
1626 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
1628 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
1629 INTERNET_STATUS_HANDLE_CLOSING
, lpwhr
,
1632 if (lpwhr
->lpszPath
)
1633 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszPath
);
1634 if (lpwhr
->lpszVerb
)
1635 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVerb
);
1636 if (lpwhr
->lpszHostName
)
1637 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszHostName
);
1639 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
1641 if (lpwhr
->StdHeaders
[i
].lpszField
)
1642 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszField
);
1643 if (lpwhr
->StdHeaders
[i
].lpszValue
)
1644 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszValue
);
1647 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
1649 if (lpwhr
->pCustHeaders
[i
].lpszField
)
1650 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszField
);
1651 if (lpwhr
->pCustHeaders
[i
].lpszValue
)
1652 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszValue
);
1655 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
);
1656 HeapFree(GetProcessHeap(), 0, lpwhr
);
1660 /***********************************************************************
1661 * HTTP_CloseHTTPSessionHandle (internal)
1663 * Deallocate session handle
1666 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs
)
1668 LPWININETAPPINFOA hIC
= NULL
;
1671 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
1673 SendAsyncCallback(hIC
, lpwhs
, lpwhs
->hdr
.dwContext
,
1674 INTERNET_STATUS_HANDLE_CLOSING
, lpwhs
,
1677 if (lpwhs
->lpszServerName
)
1678 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
1679 if (lpwhs
->lpszUserName
)
1680 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszUserName
);
1681 HeapFree(GetProcessHeap(), 0, lpwhs
);
1685 /***********************************************************************
1686 * HTTP_GetCustomHeaderIndex (internal)
1688 * Return index of custom header from header array
1691 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
)
1695 TRACE("%s\n", lpszField
);
1697 for (index
= 0; index
< lpwhr
->nCustHeaders
; index
++)
1699 if (!strcasecmp(lpwhr
->pCustHeaders
[index
].lpszField
, lpszField
))
1704 if (index
>= lpwhr
->nCustHeaders
)
1707 TRACE("Return: %d\n", index
);
1712 /***********************************************************************
1713 * HTTP_InsertCustomHeader (internal)
1715 * Insert header into array
1718 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
)
1721 LPHTTPHEADERA lph
= NULL
;
1723 TRACE("--> %s: %s\n", lpHdr
->lpszField
, lpHdr
->lpszValue
);
1724 count
= lpwhr
->nCustHeaders
+ 1;
1726 lph
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpwhr
->pCustHeaders
, sizeof(HTTPHEADERA
) * count
);
1728 lph
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HTTPHEADERA
) * count
);
1732 lpwhr
->pCustHeaders
= lph
;
1733 lpwhr
->pCustHeaders
[count
-1].lpszField
= HTTP_strdup(lpHdr
->lpszField
);
1734 lpwhr
->pCustHeaders
[count
-1].lpszValue
= HTTP_strdup(lpHdr
->lpszValue
);
1735 lpwhr
->pCustHeaders
[count
-1].wFlags
= lpHdr
->wFlags
;
1736 lpwhr
->pCustHeaders
[count
-1].wCount
= lpHdr
->wCount
;
1737 lpwhr
->nCustHeaders
++;
1741 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1745 TRACE("%d <--\n", count
-1);
1750 /***********************************************************************
1751 * HTTP_DeleteCustomHeader (internal)
1753 * Delete header from array
1756 BOOL
HTTP_DeleteCustomHeader(INT index
)
1762 /***********************************************************************
1763 * IsHostInProxyBypassList (@)
1768 BOOL WINAPI
IsHostInProxyBypassList(DWORD flags
, LPCSTR szHost
, DWORD length
)
1770 FIXME("STUB: flags=%ld host=%s length=%ld\n",flags
,szHost
,length
);