Nikolay Sivov : msxml3: Implement response headers access methods.
Alexandre Julliard
julliard at winehq.org
Mon Dec 19 13:39:22 CST 2011
Module: wine
Branch: master
Commit: 02414775e9b25346b178775d971ddd6a14377b56
URL: http://source.winehq.org/git/wine.git/?a=commit;h=02414775e9b25346b178775d971ddd6a14377b56
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Sun Dec 18 21:00:24 2011 +0300
msxml3: Implement response headers access methods.
---
dlls/msxml3/httprequest.c | 137 +++++++++++++++++++++++++++++++++++++++----
dlls/msxml3/tests/domdoc.c | 25 ++++++++-
2 files changed, 148 insertions(+), 14 deletions(-)
diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c
index cf4afe4..26241dd 100644
--- a/dlls/msxml3/httprequest.c
+++ b/dlls/msxml3/httprequest.c
@@ -56,7 +56,7 @@ static const WCHAR crlfW[] = {'\r','\n',0};
typedef struct BindStatusCallback BindStatusCallback;
-struct reqheader
+struct httpheader
{
struct list entry;
BSTR header;
@@ -80,6 +80,9 @@ typedef struct
struct list reqheaders;
/* cached resulting custom request headers string length in WCHARs */
LONG reqheader_size;
+ /* response headers */
+ struct list respheaders;
+ BSTR raw_respheaders;
/* credentials */
BSTR user;
@@ -126,6 +129,22 @@ static void httprequest_setreadystate(httprequest *This, READYSTATE state)
}
}
+static void free_response_headers(httprequest *This)
+{
+ struct httpheader *header, *header2;
+
+ LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->respheaders, struct httpheader, entry)
+ {
+ list_remove(&header->entry);
+ SysFreeString(header->header);
+ SysFreeString(header->value);
+ heap_free(header);
+ }
+
+ SysFreeString(This->raw_respheaders);
+ This->raw_respheaders = NULL;
+}
+
struct BindStatusCallback
{
IBindStatusCallback IBindStatusCallback_iface;
@@ -386,7 +405,7 @@ static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *ifac
LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers)
{
BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
- const struct reqheader *entry;
+ const struct httpheader *entry;
WCHAR *buff, *ptr;
TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(url), debugstr_w(headers), reserved, add_headers);
@@ -399,7 +418,7 @@ static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *ifac
if (!buff) return E_OUTOFMEMORY;
ptr = buff;
- LIST_FOR_EACH_ENTRY(entry, &This->request->reqheaders, struct reqheader, entry)
+ LIST_FOR_EACH_ENTRY(entry, &This->request->reqheaders, struct httpheader, entry)
{
lstrcpyW(ptr, entry->header);
ptr += SysStringLen(entry->header);
@@ -419,6 +438,37 @@ static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *ifac
return S_OK;
}
+static void add_response_header(httprequest *This, const WCHAR *data, int len)
+{
+ struct httpheader *entry;
+ const WCHAR *ptr = data;
+ BSTR header, value;
+
+ while (*ptr)
+ {
+ if (*ptr == ':')
+ {
+ header = SysAllocStringLen(data, ptr-data);
+ /* skip leading spaces for a value */
+ while (*++ptr == ' ')
+ ;
+ value = SysAllocStringLen(ptr, len-(ptr-data));
+ break;
+ }
+ ptr++;
+ }
+
+ if (!*ptr) return;
+
+ /* new header */
+ TRACE("got header %s:%s\n", debugstr_w(header), debugstr_w(value));
+
+ entry = heap_alloc(sizeof(*header));
+ entry->header = header;
+ entry->value = value;
+ list_add_head(&This->respheaders, &entry->entry);
+}
+
static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD code,
LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
{
@@ -428,6 +478,28 @@ static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD c
debugstr_w(req_headers), add_reqheaders);
This->request->status = code;
+ /* store headers */
+ free_response_headers(This->request);
+ if (resp_headers)
+ {
+ const WCHAR *ptr, *line;
+
+ ptr = line = resp_headers;
+
+ /* skip status line */
+ while (*ptr)
+ {
+ if (*ptr == '\r' && *(ptr+1) == '\n')
+ {
+ line = ++ptr+1;
+ break;
+ }
+ ptr++;
+ }
+
+ /* store as unparsed string for now */
+ This->request->raw_respheaders = SysAllocString(line);
+ }
return S_OK;
}
@@ -563,7 +635,7 @@ static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
if ( ref == 0 )
{
- struct reqheader *header, *header2;
+ struct httpheader *header, *header2;
if (This->site)
IUnknown_Release( This->site );
@@ -573,13 +645,15 @@ static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
SysFreeString(This->password);
/* request headers */
- LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->reqheaders, struct reqheader, entry)
+ LIST_FOR_EACH_ENTRY_SAFE(header, header2, &This->reqheaders, struct httpheader, entry)
{
list_remove(&header->entry);
SysFreeString(header->header);
SysFreeString(header->value);
heap_free(header);
}
+ /* response headers */
+ free_response_headers(This);
/* detach callback object */
BindStatusCallback_Detach(This->bsc);
@@ -719,7 +793,7 @@ static HRESULT WINAPI httprequest_open(IXMLHTTPRequest *iface, BSTR method, BSTR
static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR header, BSTR value)
{
httprequest *This = impl_from_IXMLHTTPRequest( iface );
- struct reqheader *entry;
+ struct httpheader *entry;
TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value));
@@ -728,7 +802,7 @@ static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR
if (!value) return E_INVALIDARG;
/* replace existing header value if already added */
- LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct reqheader, entry)
+ LIST_FOR_EACH_ENTRY(entry, &This->reqheaders, struct httpheader, entry)
{
if (lstrcmpW(entry->header, header) == 0)
{
@@ -760,22 +834,56 @@ static HRESULT WINAPI httprequest_setRequestHeader(IXMLHTTPRequest *iface, BSTR
return S_OK;
}
-static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR bstrHeader, BSTR *pbstrValue)
+static HRESULT WINAPI httprequest_getResponseHeader(IXMLHTTPRequest *iface, BSTR header, BSTR *value)
{
httprequest *This = impl_from_IXMLHTTPRequest( iface );
+ struct httpheader *entry;
- FIXME("stub (%p) %s %p\n", This, debugstr_w(bstrHeader), pbstrValue);
+ TRACE("(%p)->(%s %p)\n", This, debugstr_w(header), value);
- return E_NOTIMPL;
+ if (!header || !value) return E_INVALIDARG;
+
+ if (This->raw_respheaders && list_empty(&This->respheaders))
+ {
+ WCHAR *ptr, *line;
+
+ ptr = line = This->raw_respheaders;
+ while (*ptr)
+ {
+ if (*ptr == '\r' && *(ptr+1) == '\n')
+ {
+ add_response_header(This, line, ptr-line);
+ ptr++; line = ++ptr;
+ continue;
+ }
+ ptr++;
+ }
+ }
+
+ LIST_FOR_EACH_ENTRY(entry, &This->respheaders, struct httpheader, entry)
+ {
+ if (!strcmpiW(entry->header, header))
+ {
+ *value = SysAllocString(entry->value);
+ TRACE("header value %s\n", debugstr_w(*value));
+ return S_OK;
+ }
+ }
+
+ return S_FALSE;
}
-static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *pbstrHeaders)
+static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface, BSTR *respheaders)
{
httprequest *This = impl_from_IXMLHTTPRequest( iface );
- FIXME("stub (%p) %p\n", This, pbstrHeaders);
+ TRACE("(%p)->(%p)\n", This, respheaders);
- return E_NOTIMPL;
+ if (!respheaders) return E_INVALIDARG;
+
+ *respheaders = SysAllocString(This->raw_respheaders);
+
+ return S_OK;
}
static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT body)
@@ -1189,6 +1297,9 @@ HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
req->status = 0;
req->reqheader_size = 0;
list_init(&req->reqheaders);
+ list_init(&req->respheaders);
+ req->raw_respheaders = NULL;
+
req->site = NULL;
req->safeopt = 0;
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index 0a2dbcf..86d0cbf 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -4690,7 +4690,7 @@ static void test_XMLHTTP(void)
IXMLHttpRequest *xhr;
IObjectSafety *safety;
IObjectWithSite *obj_site, *obj_site2;
- BSTR bstrResponse, url;
+ BSTR bstrResponse, url, str, str1;
VARIANT dummy;
VARIANT async;
VARIANT varbody;
@@ -4840,6 +4840,29 @@ static void test_XMLHTTP(void)
}
EXPECT_HR(hr, S_OK);
+ /* response headers */
+ hr = IXMLHttpRequest_getAllResponseHeaders(xhr, NULL);
+ EXPECT_HR(hr, E_INVALIDARG);
+ hr = IXMLHttpRequest_getAllResponseHeaders(xhr, &str);
+ EXPECT_HR(hr, S_OK);
+ /* status line is stripped already */
+ ok(memcmp(str, _bstr_("HTTP"), 4*sizeof(WCHAR)), "got response headers %s\n", wine_dbgstr_w(str));
+ ok(*str, "got empty headers\n");
+ hr = IXMLHttpRequest_getAllResponseHeaders(xhr, &str1);
+ EXPECT_HR(hr, S_OK);
+ ok(str1 != str, "got %p\n", str1);
+ SysFreeString(str1);
+ SysFreeString(str);
+
+ hr = IXMLHttpRequest_getResponseHeader(xhr, NULL, NULL);
+ EXPECT_HR(hr, E_INVALIDARG);
+ hr = IXMLHttpRequest_getResponseHeader(xhr, _bstr_("Date"), NULL);
+ EXPECT_HR(hr, E_INVALIDARG);
+ hr = IXMLHttpRequest_getResponseHeader(xhr, _bstr_("Date"), &str);
+ EXPECT_HR(hr, S_OK);
+ ok(*str != ' ', "got leading space in header %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+
/* status code after ::send() */
status = 0xdeadbeef;
hr = IXMLHttpRequest_get_status(xhr, &status);
More information about the wine-cvs
mailing list