winhttp: Implement WinHttpAddRequestHeaders.

This commit is contained in:
Hans Leidekker 2008-08-20 11:35:39 +02:00 committed by Alexandre Julliard
parent fcb0e3a9d1
commit 8f1d818bf3
6 changed files with 336 additions and 23 deletions

View file

@ -9,6 +9,7 @@ IMPORTS = wininet kernel32
C_SRCS = \
handle.c \
main.c \
request.c \
session.c
@MAKE_DLL_RULES@

View file

@ -176,18 +176,6 @@ BOOL WINAPI WinHttpQueryHeaders (HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR
return FALSE;
}
/***********************************************************************
* WinHttpAddRequestHeaders (winhttp.@)
*/
BOOL WINAPI WinHttpAddRequestHeaders (HINTERNET hRequest, LPCWSTR pwszHeaders,
DWORD dwHeadersLength, DWORD dwModifiers)
{
FIXME("(%s, %d, %d): stub\n", debugstr_w(pwszHeaders), dwHeadersLength, dwModifiers);
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
BOOL WINAPI InternetCrackUrlW( LPCWSTR, DWORD, DWORD, LPURL_COMPONENTSW );
BOOL WINAPI InternetCreateUrlW( LPURL_COMPONENTS, DWORD, LPWSTR, LPDWORD );

320
dlls/winhttp/request.c Normal file
View file

@ -0,0 +1,320 @@
/*
* Copyright 2008 Hans Leidekker for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include "wine/debug.h"
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winhttp.h"
#include "winhttp_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
static void free_header( header_t *header )
{
heap_free( header->field );
heap_free( header->value );
heap_free( header );
}
static BOOL valid_token_char( WCHAR c )
{
if (c < 32 || c == 127) return FALSE;
switch (c)
{
case '(': case ')':
case '<': case '>':
case '@': case ',':
case ';': case ':':
case '\\': case '\"':
case '/': case '[':
case ']': case '?':
case '=': case '{':
case '}': case ' ':
case '\t':
return FALSE;
default:
return TRUE;
}
}
static header_t *parse_header( LPCWSTR string )
{
const WCHAR *p, *q;
header_t *header;
int len;
p = string;
if (!(q = strchrW( p, ':' )))
{
WARN("no ':' in line %s\n", debugstr_w(string));
return NULL;
}
if (q == string)
{
WARN("empty field name in line %s\n", debugstr_w(string));
return NULL;
}
while (*p != ':')
{
if (!valid_token_char( *p ))
{
WARN("invalid character in field name %s\n", debugstr_w(string));
return NULL;
}
p++;
}
len = q - string;
if (!(header = heap_alloc_zero( sizeof(header_t) ))) return NULL;
if (!(header->field = heap_alloc( (len + 1) * sizeof(WCHAR) )))
{
heap_free( header );
return NULL;
}
memcpy( header->field, string, len * sizeof(WCHAR) );
header->field[len] = 0;
q++; /* skip past colon */
while (*q == ' ') q++;
if (!*q)
{
WARN("no value in line %s\n", debugstr_w(string));
return header;
}
len = strlenW( q );
if (!(header->value = heap_alloc( (len + 1) * sizeof(WCHAR) )))
{
free_header( header );
return NULL;
}
memcpy( header->value, q, len * sizeof(WCHAR) );
header->value[len] = 0;
return header;
}
static int get_header_index( request_t *request, LPCWSTR field, int requested_index, BOOL request_only )
{
int index;
TRACE("%s\n", debugstr_w(field));
for (index = 0; index < request->num_headers; index++)
{
if (strcmpiW( request->headers[index].field, field )) continue;
if (request_only && !request->headers[index].is_request) continue;
if (!request_only && request->headers[index].is_request) continue;
if (!requested_index) break;
requested_index--;
}
if (index >= request->num_headers) index = -1;
TRACE("returning %d\n", index);
return index;
}
static BOOL insert_header( request_t *request, header_t *header )
{
DWORD count;
header_t *hdrs;
TRACE("inserting %s: %s\n", debugstr_w(header->field), debugstr_w(header->value));
count = request->num_headers + 1;
if (count > 1)
hdrs = heap_realloc_zero( request->headers, sizeof(header_t) * count );
else
hdrs = heap_alloc_zero( sizeof(header_t) * count );
if (hdrs)
{
request->headers = hdrs;
request->headers[count - 1].field = strdupW( header->field );
request->headers[count - 1].value = strdupW( header->value );
request->headers[count - 1].is_request = header->is_request;
request->num_headers++;
return TRUE;
}
return FALSE;
}
static BOOL delete_header( request_t *request, DWORD index )
{
if (!request->num_headers) return FALSE;
if (index >= request->num_headers) return FALSE;
request->num_headers--;
heap_free( request->headers[index].field );
heap_free( request->headers[index].value );
memmove( &request->headers[index], &request->headers[index + 1], (request->num_headers - index) * sizeof(header_t) );
memset( &request->headers[request->num_headers], 0, sizeof(header_t) );
return TRUE;
}
static BOOL process_header( request_t *request, LPCWSTR field, LPCWSTR value, DWORD flags, BOOL request_only )
{
int index;
header_t *header;
TRACE("%s: %s 0x%08x\n", debugstr_w(field), debugstr_w(value), flags);
/* replace wins out over add */
if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) flags &= ~WINHTTP_ADDREQ_FLAG_ADD;
if (flags & WINHTTP_ADDREQ_FLAG_ADD) index = -1;
else
index = get_header_index( request, field, 0, request_only );
if (index >= 0)
{
if (flags & WINHTTP_ADDREQ_FLAG_ADD_IF_NEW) return FALSE;
header = &request->headers[index];
}
else if (value)
{
header_t hdr;
hdr.field = (LPWSTR)field;
hdr.value = (LPWSTR)value;
hdr.is_request = request_only;
return insert_header( request, &hdr );
}
/* no value to delete */
else return TRUE;
if (flags & WINHTTP_ADDREQ_FLAG_REPLACE)
{
delete_header( request, index );
if (value)
{
header_t hdr;
hdr.field = (LPWSTR)field;
hdr.value = (LPWSTR)value;
hdr.is_request = request_only;
return insert_header( request, &hdr );
}
return TRUE;
}
else if (flags & (WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON))
{
WCHAR sep, *tmp;
int len, orig_len, value_len;
orig_len = strlenW( header->value );
value_len = strlenW( value );
if (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) sep = ',';
else sep = ';';
len = orig_len + value_len + 2;
if ((tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) )))
{
header->value = tmp;
header->value[orig_len] = sep;
orig_len++;
header->value[orig_len] = ' ';
orig_len++;
memcpy( &header->value[orig_len], value, value_len * sizeof(WCHAR) );
header->value[len] = 0;
return TRUE;
}
}
return TRUE;
}
static BOOL add_request_headers( request_t *request, LPCWSTR headers, DWORD len, DWORD flags )
{
BOOL ret = FALSE;
WCHAR *buffer, *p, *q;
header_t *header;
if (len == ~0UL) len = strlenW( headers );
if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE;
strcpyW( buffer, headers );
p = buffer;
do
{
q = p;
while (*q)
{
if (q[0] == '\r' && q[1] == '\n') break;
q++;
}
if (!*p) break;
if (*q == '\r')
{
*q = 0;
q += 2; /* jump over \r\n */
}
if ((header = parse_header( p )))
{
ret = process_header( request, header->field, header->value, flags, TRUE );
free_header( header );
}
p = q;
} while (ret);
heap_free( buffer );
return ret;
}
/***********************************************************************
* WinHttpAddRequestHeaders (winhttp.@)
*/
BOOL WINAPI WinHttpAddRequestHeaders( HINTERNET hrequest, LPCWSTR headers, DWORD len, DWORD flags )
{
BOOL ret;
request_t *request;
TRACE("%p, %s, 0x%x, 0x%08x\n", hrequest, debugstr_w(headers), len, flags);
if (!headers)
{
set_last_error( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (!(request = (request_t *)grab_object( hrequest )))
{
set_last_error( ERROR_INVALID_HANDLE );
return FALSE;
}
if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
{
release_object( &request->hdr );
set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
return FALSE;
}
ret = add_request_headers( request, headers, len, flags );
release_object( &request->hdr );
return ret;
}

View file

@ -31,7 +31,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
static void set_last_error( DWORD error )
void set_last_error( DWORD error )
{
/* FIXME */
SetLastError( error );

View file

@ -243,7 +243,7 @@ static void test_WinHttpAddHeaders(void)
test_header_name, buffer, &len, &index);
ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded, found 'Warning' header.");
ret = WinHttpAddRequestHeaders(request, test_headers[0], -1L, WINHTTP_ADDREQ_FLAG_ADD);
todo_wine ok(ret == TRUE, "WinHttpAddRequestHeader failed to add new header, got %d with error %u.\n", ret, GetLastError());
ok(ret == TRUE, "WinHttpAddRequestHeader failed to add new header, got %d with error %u.\n", ret, GetLastError());
index = 0;
len = sizeof(buffer);
@ -337,7 +337,7 @@ static void test_WinHttpAddHeaders(void)
/* tests for more indices */
ret = WinHttpAddRequestHeaders(request, test_headers[1], -1L, WINHTTP_ADDREQ_FLAG_ADD);
todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header: %d\n", ret);
ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header: %d\n", ret);
index = 0;
len = sizeof(buffer);
@ -362,7 +362,7 @@ static void test_WinHttpAddHeaders(void)
}
ret = WinHttpAddRequestHeaders(request, test_headers[2], -1L, WINHTTP_ADDREQ_FLAG_REPLACE);
todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header.\n");
ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header.\n");
index = 0;
len = sizeof(buffer);
@ -418,7 +418,7 @@ static void test_WinHttpAddHeaders(void)
/* coalesce flag */
ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_COALESCE);
todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE.\n");
ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE.\n");
index = 0;
len = sizeof(buffer);
@ -448,7 +448,7 @@ static void test_WinHttpAddHeaders(void)
/* coalesce with comma flag */
ret = WinHttpAddRequestHeaders(request, test_headers[4], -1L, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA);
todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA.\n");
ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA.\n");
index = 0;
len = sizeof(buffer);
@ -479,7 +479,7 @@ static void test_WinHttpAddHeaders(void)
/* coalesce with semicolon flag */
ret = WinHttpAddRequestHeaders(request, test_headers[5], -1L, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON);
todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON.\n");
ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON.\n");
index = 0;
len = sizeof(buffer);
@ -509,8 +509,7 @@ static void test_WinHttpAddHeaders(void)
/* add and replace flags */
ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE);
todo_wine ok(ret == TRUE,
"WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE.\n");
ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE.\n");
index = 0;
len = sizeof(buffer);

View file

@ -90,8 +90,7 @@ typedef struct
{
LPWSTR field;
LPWSTR value;
WORD flags;
WORD count;
BOOL is_request; /* part of request headers? */
} header_t;
typedef struct
@ -116,6 +115,7 @@ void release_object( object_header_t * );
HINTERNET alloc_handle( object_header_t * );
BOOL free_handle( HINTERNET );
void set_last_error( DWORD );
void send_callback( object_header_t *, DWORD, LPVOID, DWORD );
static inline void *heap_alloc( SIZE_T size )
@ -128,6 +128,11 @@ static inline void *heap_alloc_zero( SIZE_T size )
return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
}
static inline void *heap_realloc( LPVOID mem, SIZE_T size )
{
return HeapReAlloc( GetProcessHeap(), 0, mem, size );
}
static inline void *heap_realloc_zero( LPVOID mem, SIZE_T size )
{
return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size );