return ret;
}
-typedef enum {
- BLOCKING_ALLOW,
- BLOCKING_DISALLOW,
- BLOCKING_WAITALL
-} blocking_mode_t;
-
struct data_stream_vtbl_t {
- DWORD (*get_avail_data)(data_stream_t*,http_request_t*);
BOOL (*end_of_data)(data_stream_t*,http_request_t*);
- DWORD (*read)(data_stream_t*,http_request_t*,BYTE*,DWORD,DWORD*,blocking_mode_t);
+ DWORD (*read)(data_stream_t*,http_request_t*,BYTE*,DWORD,DWORD*,BOOL);
BOOL (*drain_content)(data_stream_t*,http_request_t*);
void (*destroy)(data_stream_t*);
};
BOOL end_of_data;
} gzip_stream_t;
-static DWORD gzip_get_avail_data(data_stream_t *stream, http_request_t *req)
-{
- /* Allow reading only from read buffer */
- return 0;
-}
-
static BOOL gzip_end_of_data(data_stream_t *stream, http_request_t *req)
{
gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
}
static DWORD gzip_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
- DWORD *read, blocking_mode_t blocking_mode)
+ DWORD *read, BOOL allow_blocking)
{
gzip_stream_t *gzip_stream = (gzip_stream_t*)stream;
z_stream *zstream = &gzip_stream->zstream;
int zres;
DWORD res = ERROR_SUCCESS;
- TRACE("(%d %d)\n", size, blocking_mode);
+ TRACE("(%d %x)\n", size, allow_blocking);
while(size && !gzip_stream->end_of_data) {
if(!gzip_stream->buf_size) {
gzip_stream->buf_pos = 0;
}
res = gzip_stream->parent_stream->vtbl->read(gzip_stream->parent_stream, req, gzip_stream->buf+gzip_stream->buf_size,
- sizeof(gzip_stream->buf)-gzip_stream->buf_size, ¤t_read, blocking_mode);
- gzip_stream->buf_size += current_read;
+ sizeof(gzip_stream->buf)-gzip_stream->buf_size, ¤t_read, allow_blocking);
if(res != ERROR_SUCCESS)
break;
+ gzip_stream->buf_size += current_read;
if(!current_read) {
- if(blocking_mode != BLOCKING_DISALLOW) {
- WARN("unexpected end of data\n");
- gzip_stream->end_of_data = TRUE;
- }
+ WARN("unexpected end of data\n");
+ gzip_stream->end_of_data = TRUE;
break;
}
}
break;
}
- if(ret_read && blocking_mode == BLOCKING_ALLOW)
- blocking_mode = BLOCKING_DISALLOW;
+ if(ret_read)
+ allow_blocking = FALSE;
}
TRACE("read %u bytes\n", ret_read);
+ if(ret_read)
+ res = ERROR_SUCCESS;
*read = ret_read;
return res;
}
}
static const data_stream_vtbl_t gzip_stream_vtbl = {
- gzip_get_avail_data,
gzip_end_of_data,
gzip_read,
gzip_drain_content,
if (!(req->session->appInfo->proxyPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
return ERROR_SUCCESS;
- case INTERNET_OPTION_HTTP_DECODING:
- if(size != sizeof(BOOL))
- return ERROR_INVALID_PARAMETER;
- req->decoding = *(BOOL*)buffer;
- return ERROR_SUCCESS;
}
return INET_SetOption(hdr, option, buffer, size);
return !req->read_size && req->data_stream->vtbl->end_of_data(req->data_stream, req);
}
-static DWORD read_http_stream(http_request_t *req, BYTE *buf, DWORD size, DWORD *read, blocking_mode_t blocking_mode)
+static DWORD read_http_stream(http_request_t *req, BYTE *buf, DWORD size, DWORD *read, BOOL allow_blocking)
{
DWORD res;
- res = req->data_stream->vtbl->read(req->data_stream, req, buf, size, read, blocking_mode);
+ res = req->data_stream->vtbl->read(req->data_stream, req, buf, size, read, allow_blocking);
+ if(res != ERROR_SUCCESS)
+ *read = 0;
assert(*read <= size);
if(req->hCacheFile) {
FIXME("WriteFile failed: %u\n", GetLastError());
}
- if(req->data_stream->vtbl->end_of_data(req->data_stream, req))
+ if((res == ERROR_SUCCESS && !*read) || req->data_stream->vtbl->end_of_data(req->data_stream, req))
commit_cache_entry(req);
}
}
/* fetch some more data into the read buffer (the read section must be held) */
-static DWORD refill_read_buffer(http_request_t *req, blocking_mode_t blocking_mode, DWORD *read_bytes)
+static DWORD refill_read_buffer(http_request_t *req, BOOL allow_blocking, DWORD *read_bytes)
{
DWORD res, read=0;
}
res = read_http_stream(req, req->read_buf+req->read_size, sizeof(req->read_buf) - req->read_size,
- &read, blocking_mode);
+ &read, allow_blocking);
+ if(res != ERROR_SUCCESS)
+ return res;
+
req->read_size += read;
TRACE("read %u bytes, read_size %u\n", read, req->read_size);
return res;
}
-/* return the size of data available to be read immediately (the read section must be held) */
-static DWORD get_avail_data( http_request_t *req )
-{
- DWORD avail = req->read_size;
-
- /*
- * Different Windows versions have different limits of returned data, but all
- * of them return no more than centrain amount. We use READ_BUFFER_SIZE as a limit.
- */
- if(avail < READ_BUFFER_SIZE)
- avail += req->data_stream->vtbl->get_avail_data(req->data_stream, req);
-
- return min(avail, READ_BUFFER_SIZE);
-}
-
-static DWORD netconn_get_avail_data(data_stream_t *stream, http_request_t *req)
-{
- netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
- DWORD avail = 0;
-
- if(is_valid_netconn(req->netconn))
- NETCON_query_data_available(req->netconn, &avail);
- return netconn_stream->content_length == ~0u
- ? avail
- : min(avail, netconn_stream->content_length-netconn_stream->content_read);
-}
-
static BOOL netconn_end_of_data(data_stream_t *stream, http_request_t *req)
{
netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
}
static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
- DWORD *read, blocking_mode_t blocking_mode)
+ DWORD *read, BOOL allow_blocking)
{
netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
DWORD res = ERROR_SUCCESS;
- int len = 0, ret = 0;
+ int ret = 0;
size = min(size, netconn_stream->content_length-netconn_stream->content_read);
if(size && is_valid_netconn(req->netconn)) {
- while((res = NETCON_recv(req->netconn, buf+ret, size-ret, blocking_mode != BLOCKING_DISALLOW, &len)) == ERROR_SUCCESS) {
- if(!len) {
+ res = NETCON_recv(req->netconn, buf, size, allow_blocking, &ret);
+ if(res == ERROR_SUCCESS) {
+ if(!ret)
netconn_stream->content_length = netconn_stream->content_read;
- break;
- }
- ret += len;
- netconn_stream->content_read += len;
- if(blocking_mode != BLOCKING_WAITALL || size == ret)
- break;
+ netconn_stream->content_read += ret;
}
-
- if(ret || (blocking_mode == BLOCKING_DISALLOW && res == WSAEWOULDBLOCK))
- res = ERROR_SUCCESS;
}
- TRACE("read %u bytes\n", ret);
+ TRACE("res %u read %u bytes\n", res, ret);
*read = ret;
return res;
}
{
netconn_stream_t *netconn_stream = (netconn_stream_t*)stream;
BYTE buf[1024];
- int len;
+ int len, res;
+ size_t size;
- if(netconn_end_of_data(stream, req))
- return TRUE;
+ if(netconn_stream->content_length == ~0u)
+ return FALSE;
- do {
- if(NETCON_recv(req->netconn, buf, sizeof(buf), FALSE, &len) != ERROR_SUCCESS)
+ while(netconn_stream->content_read < netconn_stream->content_length) {
+ size = min(sizeof(buf), netconn_stream->content_length-netconn_stream->content_read);
+ res = NETCON_recv(req->netconn, buf, size, FALSE, &len);
+ if(res || !len)
return FALSE;
netconn_stream->content_read += len;
- }while(netconn_stream->content_read < netconn_stream->content_length);
+ }
return TRUE;
}
}
static const data_stream_vtbl_t netconn_stream_vtbl = {
- netconn_get_avail_data,
netconn_end_of_data,
netconn_read,
netconn_drain_content,
}
static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size,
- DWORD *read, blocking_mode_t blocking_mode)
+ DWORD *read, BOOL allow_blocking)
{
chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
DWORD ret_read = 0, res = ERROR_SUCCESS;
case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA:
case CHUNKED_STREAM_STATE_DISCARD_EOL_AT_END:
chunked_stream->buf_pos = 0;
- res = NETCON_recv(req->netconn, chunked_stream->buf, sizeof(chunked_stream->buf), blocking_mode != BLOCKING_DISALLOW, &read_bytes);
+ res = NETCON_recv(req->netconn, chunked_stream->buf, sizeof(chunked_stream->buf), allow_blocking, &read_bytes);
if(res == ERROR_SUCCESS && read_bytes) {
chunked_stream->buf_size += read_bytes;
}else if(res == WSAEWOULDBLOCK) {
+ if(ret_read)
+ res = ERROR_SUCCESS;
continue_read = FALSE;
continue;
}else {
chunked_stream->buf_size -= read_bytes;
}else {
res = NETCON_recv(req->netconn, (char*)buf+ret_read, read_bytes,
- blocking_mode != BLOCKING_DISALLOW, (int*)&read_bytes);
+ allow_blocking, (int*)&read_bytes);
if(res != ERROR_SUCCESS) {
continue_read = FALSE;
break;
ret_read += read_bytes;
if(!chunked_stream->chunk_size)
chunked_stream->state = CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA;
- if(blocking_mode == BLOCKING_ALLOW)
- blocking_mode = BLOCKING_DISALLOW;
+ allow_blocking = FALSE;
break;
case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA:
if(ret_read)
res = ERROR_SUCCESS;
- if(res != ERROR_SUCCESS && res != WSAEWOULDBLOCK)
+ if(res != ERROR_SUCCESS)
return res;
TRACE("read %d bytes\n", ret_read);
return ERROR_SUCCESS;
}
-static DWORD chunked_get_avail_data(data_stream_t *stream, http_request_t *req)
-{
- chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
- DWORD avail = 0;
-
- if(chunked_stream->state != CHUNKED_STREAM_STATE_READING_CHUNK) {
- DWORD res, read;
-
- /* try to process to the next chunk */
- res = chunked_read(stream, req, NULL, 0, &read, BLOCKING_DISALLOW);
- if(res != ERROR_SUCCESS || chunked_stream->state != CHUNKED_STREAM_STATE_READING_CHUNK)
- return 0;
- }
-
- if(is_valid_netconn(req->netconn) && chunked_stream->buf_size < chunked_stream->chunk_size)
- NETCON_query_data_available(req->netconn, &avail);
-
- return min(avail + chunked_stream->buf_size, chunked_stream->chunk_size);
-}
-
static BOOL chunked_drain_content(data_stream_t *stream, http_request_t *req)
{
chunked_stream_t *chunked_stream = (chunked_stream_t*)stream;
}
static const data_stream_vtbl_t chunked_stream_vtbl = {
- chunked_get_avail_data,
chunked_end_of_data,
chunked_read,
chunked_drain_content,
request->contentLength = ~0u;
}
- if(request->decoding) {
+ if(request->hdr.decoding) {
int encoding_idx;
static const WCHAR deflateW[] = {'d','e','f','l','a','t','e',0};
sizeof(INTERNET_ASYNC_RESULT));
}
-static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif, DWORD *ret_size)
+static void HTTP_ReceiveRequestData(http_request_t *req)
{
- DWORD res, read = 0, avail = 0;
- blocking_mode_t mode;
+ DWORD res, read = 0;
TRACE("%p\n", req);
EnterCriticalSection( &req->read_section );
- mode = first_notif && req->read_size ? BLOCKING_DISALLOW : BLOCKING_ALLOW;
- res = refill_read_buffer(req, mode, &read);
+ res = refill_read_buffer(req, FALSE, &read);
if(res == ERROR_SUCCESS)
- avail = get_avail_data(req);
+ read += req->read_size;
LeaveCriticalSection( &req->read_section );
- if(res != ERROR_SUCCESS || (mode != BLOCKING_DISALLOW && !read)) {
+ if(res != WSAEWOULDBLOCK && (res != ERROR_SUCCESS || !read)) {
WARN("res %u read %u, closing connection\n", res, read);
http_release_netconn(req, FALSE);
}
- if(res != ERROR_SUCCESS) {
+ if(res != ERROR_SUCCESS && res != WSAEWOULDBLOCK) {
send_request_complete(req, 0, res);
return;
}
- if(ret_size)
- *ret_size = avail;
- if(first_notif)
- avail = 0;
-
- send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, avail);
+ send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, 0);
}
/* read data from the http connection (the read section must be held) */
-static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read)
+static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL allow_blocking)
{
DWORD current_read = 0, ret_read = 0;
- blocking_mode_t blocking_mode;
DWORD res = ERROR_SUCCESS;
- blocking_mode = req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC ? BLOCKING_ALLOW : BLOCKING_WAITALL;
-
EnterCriticalSection( &req->read_section );
if(req->read_size) {
memcpy(buffer, req->read_buf+req->read_pos, ret_read);
req->read_size -= ret_read;
req->read_pos += ret_read;
- if(blocking_mode == BLOCKING_ALLOW)
- blocking_mode = BLOCKING_DISALLOW;
+ allow_blocking = FALSE;
}
if(ret_read < size) {
- res = read_http_stream(req, (BYTE*)buffer+ret_read, size-ret_read, ¤t_read, blocking_mode);
- ret_read += current_read;
+ res = read_http_stream(req, (BYTE*)buffer+ret_read, size-ret_read, ¤t_read, allow_blocking);
+ if(res == ERROR_SUCCESS)
+ ret_read += current_read;
+ else if(res == WSAEWOULDBLOCK && ret_read)
+ res = ERROR_SUCCESS;
}
LeaveCriticalSection( &req->read_section );
*read = ret_read;
TRACE( "retrieved %u bytes (%u)\n", ret_read, req->contentLength );
- if(size && !ret_read)
+ if(res != WSAEWOULDBLOCK && (!ret_read || res != ERROR_SUCCESS))
http_release_netconn(req, res == ERROR_SUCCESS);
return res;
DWORD bytes_read, res;
BYTE buf[4096];
- res = HTTPREQ_Read(req, buf, sizeof(buf), &bytes_read);
+ res = HTTPREQ_Read(req, buf, sizeof(buf), &bytes_read, TRUE);
if(res != ERROR_SUCCESS) {
ret = FALSE;
break;
task_header_t hdr;
void *buf;
DWORD size;
+ DWORD read_pos;
DWORD *ret_read;
-} read_file_ex_task_t;
+} read_file_task_t;
-static void AsyncReadFileExProc(task_header_t *hdr)
+static void async_read_file_proc(task_header_t *hdr)
{
- read_file_ex_task_t *task = (read_file_ex_task_t*)hdr;
+ read_file_task_t *task = (read_file_task_t*)hdr;
http_request_t *req = (http_request_t*)task->hdr.hdr;
- DWORD res = ERROR_SUCCESS, read = 0, buffered = 0;
+ DWORD res = ERROR_SUCCESS, read = task->read_pos, complete_arg = 0;
- TRACE("%p\n", req);
+ TRACE("req %p buf %p size %u read_pos %u ret_read %p\n", req, task->buf, task->size, task->read_pos, task->ret_read);
+
+ if(task->buf) {
+ DWORD read_bytes;
+ while (read < task->size) {
+ res = HTTPREQ_Read(req, (char*)task->buf + read, task->size - read, &read_bytes, TRUE);
+ if (res != ERROR_SUCCESS || !read_bytes)
+ break;
+ read += read_bytes;
+ }
+ }else {
+ EnterCriticalSection(&req->read_section);
+ res = refill_read_buffer(req, TRUE, &read);
+ LeaveCriticalSection(&req->read_section);
- if(task->ret_read)
- res = HTTPREQ_Read(req, task->buf, task->size, &read);
- if(res == ERROR_SUCCESS)
- res = refill_read_buffer(req, task->ret_read ? BLOCKING_DISALLOW : BLOCKING_ALLOW, &buffered);
- if (res == ERROR_SUCCESS)
- {
if(task->ret_read)
- *task->ret_read = read;
- read += buffered;
- INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
- &read, sizeof(read));
+ complete_arg = read; /* QueryDataAvailable reports read bytes in request complete notification */
+ if(res != ERROR_SUCCESS || !read)
+ http_release_netconn(req, drain_content(req, FALSE));
}
- send_request_complete(req, res == ERROR_SUCCESS, res);
+ TRACE("res %u read %u\n", res, read);
+
+ if(task->ret_read)
+ *task->ret_read = read;
+
+ /* FIXME: We should report bytes transferred before decoding content. */
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, &read, sizeof(read));
+
+ if(res != ERROR_SUCCESS)
+ complete_arg = res;
+ send_request_complete(req, res == ERROR_SUCCESS, complete_arg);
}
-static DWORD HTTPREQ_ReadFileEx(object_header_t *hdr, void *buf, DWORD size, DWORD *ret_read,
- DWORD flags, DWORD_PTR context)
+static DWORD async_read(http_request_t *req, void *buf, DWORD size, DWORD read_pos, DWORD *ret_read)
{
+ read_file_task_t *task;
+ task = alloc_async_task(&req->hdr, async_read_file_proc, sizeof(*task));
+ if(!task)
+ return ERROR_OUTOFMEMORY;
+
+ task->buf = buf;
+ task->size = size;
+ task->read_pos = read_pos;
+ task->ret_read = ret_read;
+
+ INTERNET_AsyncCall(&task->hdr);
+ return ERROR_IO_PENDING;
+}
+
+static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD *ret_read,
+ DWORD flags, DWORD_PTR context)
+{
http_request_t *req = (http_request_t*)hdr;
- DWORD res, read, cread, error = ERROR_SUCCESS;
+ DWORD res = ERROR_SUCCESS, read = 0, cread, error = ERROR_SUCCESS;
+ BOOL allow_blocking, notify_received = FALSE;
TRACE("(%p %p %u %x)\n", req, buf, size, flags);
if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
- INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+ allow_blocking = !(req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC);
+
+ if(allow_blocking || TryEnterCriticalSection(&req->read_section)) {
+ if(allow_blocking)
+ EnterCriticalSection(&req->read_section);
+ if(hdr->dwError == ERROR_SUCCESS)
+ hdr->dwError = INTERNET_HANDLE_IN_USE;
+ else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
+ hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
+
+ if(req->read_size) {
+ read = min(size, req->read_size);
+ memcpy(buf, req->read_buf + req->read_pos, read);
+ req->read_size -= read;
+ req->read_pos += read;
+ }
- if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
- {
- read_file_ex_task_t *task;
+ if(read < size && (!read || !(flags & IRF_NO_WAIT)) && !end_of_read_data(req)) {
+ LeaveCriticalSection(&req->read_section);
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+ EnterCriticalSection( &req->read_section );
+ notify_received = TRUE;
- if (TryEnterCriticalSection( &req->read_section ))
- {
- if (get_avail_data(req) || end_of_read_data(req))
- {
- res = HTTPREQ_Read(req, buf, size, &read);
- LeaveCriticalSection( &req->read_section );
- goto done;
+ while(read < size) {
+ res = HTTPREQ_Read(req, (char*)buf+read, size-read, &cread, allow_blocking);
+ read += cread;
+ if (res != ERROR_SUCCESS || !cread)
+ break;
}
- LeaveCriticalSection( &req->read_section );
}
- task = alloc_async_task(&req->hdr, AsyncReadFileExProc, sizeof(*task));
- task->buf = buf;
- task->size = size;
- task->ret_read = (flags & IRF_NO_WAIT) ? NULL : ret_read;
-
- INTERNET_AsyncCall(&task->hdr);
-
- return ERROR_IO_PENDING;
- }
-
- read = 0;
-
- EnterCriticalSection( &req->read_section );
- if(hdr->dwError == ERROR_SUCCESS)
- hdr->dwError = INTERNET_HANDLE_IN_USE;
- else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
- hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
-
- while(1) {
- res = HTTPREQ_Read(req, (char*)buf+read, size-read, &cread);
- if(res != ERROR_SUCCESS)
- break;
-
- read += cread;
- if(read == size || end_of_read_data(req))
- break;
+ if(hdr->dwError == INTERNET_HANDLE_IN_USE)
+ hdr->dwError = ERROR_SUCCESS;
+ else
+ error = hdr->dwError;
LeaveCriticalSection( &req->read_section );
-
- INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
- &cread, sizeof(cread));
- INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
- INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
-
- EnterCriticalSection( &req->read_section );
+ }else {
+ res = WSAEWOULDBLOCK;
}
- if(hdr->dwError == INTERNET_HANDLE_IN_USE)
- hdr->dwError = ERROR_SUCCESS;
- else
- error = hdr->dwError;
-
- LeaveCriticalSection( &req->read_section );
+ if(res == WSAEWOULDBLOCK) {
+ if(!(flags & IRF_NO_WAIT))
+ return async_read(req, buf, size, read, ret_read);
+ if(!read)
+ return async_read(req, NULL, 0, 0, NULL);
+ res = ERROR_SUCCESS;
+ }
-done:
*ret_read = read;
- if (res == ERROR_SUCCESS) {
+ if (res != ERROR_SUCCESS)
+ return res;
+
+ if(notify_received)
INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
&read, sizeof(read));
- }
-
- return res==ERROR_SUCCESS ? error : res;
+ return error;
}
static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
return res;
}
-static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
+static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
{
http_request_t *req = (http_request_t*)hdr;
- DWORD res;
-
- if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
- {
- read_file_ex_task_t *task;
-
- if (TryEnterCriticalSection( &req->read_section ))
- {
- if (get_avail_data(req) || end_of_read_data(req))
- {
- res = HTTPREQ_Read(req, buffer, size, read);
- LeaveCriticalSection( &req->read_section );
- return res;
- }
- LeaveCriticalSection( &req->read_section );
- }
-
- task = alloc_async_task(&req->hdr, AsyncReadFileExProc, sizeof(*task));
- task->buf = buffer;
- task->size = size;
- task->ret_read = read;
-
- *read = 0;
- INTERNET_AsyncCall(&task->hdr);
-
- return ERROR_IO_PENDING;
- }
-
- EnterCriticalSection( &req->read_section );
- if(hdr->dwError == INTERNET_HANDLE_IN_USE)
- hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
+ DWORD res = ERROR_SUCCESS, avail = 0, error = ERROR_SUCCESS;
+ BOOL allow_blocking, notify_received = FALSE;
- res = HTTPREQ_Read(req, buffer, size, read);
- if(res == ERROR_SUCCESS)
- res = hdr->dwError;
- LeaveCriticalSection( &req->read_section );
+ TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
- return res;
-}
+ if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
+ FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
-typedef struct {
- task_header_t hdr;
- DWORD *ret_size;
-} http_data_available_task_t;
+ *available = 0;
+ allow_blocking = !(req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC);
-static void AsyncQueryDataAvailableProc(task_header_t *hdr)
-{
- http_data_available_task_t *task = (http_data_available_task_t*)hdr;
+ if(allow_blocking || TryEnterCriticalSection(&req->read_section)) {
+ if(allow_blocking)
+ EnterCriticalSection(&req->read_section);
+ if(hdr->dwError == ERROR_SUCCESS)
+ hdr->dwError = INTERNET_HANDLE_IN_USE;
+ else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
+ hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
- HTTP_ReceiveRequestData((http_request_t*)task->hdr.hdr, FALSE, task->ret_size);
-}
+ avail = req->read_size;
-static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
-{
- http_request_t *req = (http_request_t*)hdr;
+ if(!avail && !end_of_read_data(req)) {
+ LeaveCriticalSection(&req->read_section);
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+ EnterCriticalSection( &req->read_section );
+ notify_received = TRUE;
- TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
-
- if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
- {
- http_data_available_task_t *task;
-
- /* never wait, if we can't enter the section we queue an async request right away */
- if (TryEnterCriticalSection( &req->read_section ))
- {
- refill_read_buffer(req, BLOCKING_DISALLOW, NULL);
- if ((*available = get_avail_data( req ))) goto done;
- if (end_of_read_data( req )) goto done;
- LeaveCriticalSection( &req->read_section );
+ res = refill_read_buffer(req, allow_blocking, &avail);
}
- task = alloc_async_task(&req->hdr, AsyncQueryDataAvailableProc, sizeof(*task));
- task->ret_size = available;
- INTERNET_AsyncCall(&task->hdr);
- return ERROR_IO_PENDING;
- }
-
- EnterCriticalSection( &req->read_section );
+ if(hdr->dwError == INTERNET_HANDLE_IN_USE)
+ hdr->dwError = ERROR_SUCCESS;
+ else
+ error = hdr->dwError;
- if (!(*available = get_avail_data( req )) && !end_of_read_data( req ))
- {
- refill_read_buffer( req, BLOCKING_ALLOW, NULL );
- *available = get_avail_data( req );
+ LeaveCriticalSection( &req->read_section );
+ }else {
+ res = WSAEWOULDBLOCK;
}
-done:
- LeaveCriticalSection( &req->read_section );
+ if(res == WSAEWOULDBLOCK)
+ return async_read(req, NULL, 0, 0, available);
- TRACE( "returning %u\n", *available );
- return ERROR_SUCCESS;
+ if (res != ERROR_SUCCESS)
+ return res;
+
+ *available = avail;
+ if(notify_received)
+ INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
+ &avail, sizeof(avail));
+ return error;
}
static DWORD HTTPREQ_LockRequestFile(object_header_t *hdr, req_file_t **ret)
HTTPREQ_QueryOption,
HTTPREQ_SetOption,
HTTPREQ_ReadFile,
- HTTPREQ_ReadFileEx,
HTTPREQ_WriteFile,
HTTPREQ_QueryDataAvailable,
NULL,
request->hdr.htype = WH_HHTTPREQ;
request->hdr.dwFlags = dwFlags;
request->hdr.dwContext = dwContext;
+ request->hdr.decoding = session->hdr.decoding;
request->contentLength = ~0u;
request->netconn_stream.data_stream.vtbl = &netconn_stream_vtbl;
if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
return INTERNET_GetLastError();
+ if (!urlComponents.dwHostNameLength)
+ return ERROR_INTERNET_INVALID_URL;
+
if(urlComponents.nScheme == INTERNET_SCHEME_HTTP) {
if(request->hdr.dwFlags & INTERNET_FLAG_SECURE) {
TRACE("redirect from secure page to non-secure page\n");
while (isspaceW(*ptr))
ptr++;
- for (monthPtr = month; !isspace(*ptr) &&
+ for (monthPtr = month; !isspaceW(*ptr) &&
monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
monthPtr++, ptr++)
*monthPtr = *ptr;
while (isspaceW(*ptr))
ptr++;
- for (monthPtr = month; !isspace(*ptr) &&
+ for (monthPtr = month; !isspaceW(*ptr) &&
monthPtr - month < sizeof(month) / sizeof(month[0]) - 1;
monthPtr++, ptr++)
*monthPtr = *ptr;
{
if (res == ERROR_SUCCESS) {
if(bEndRequest && request->contentLength && request->bytesWritten == request->bytesToWrite)
- HTTP_ReceiveRequestData(request, TRUE, NULL);
+ HTTP_ReceiveRequestData(request);
else
send_request_complete(request,
request->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)request->hdr.hInternet : 1, 0);
create_cache_entry(request);
if (res == ERROR_SUCCESS && request->contentLength)
- HTTP_ReceiveRequestData(request, TRUE, NULL);
+ HTTP_ReceiveRequestData(request);
else
send_request_complete(request, res == ERROR_SUCCESS, res);
NULL,
NULL,
NULL,
- NULL,
NULL
};
session->hdr.dwFlags = dwFlags;
session->hdr.dwContext = dwContext;
session->hdr.dwInternalFlags |= dwInternalFlags;
+ session->hdr.decoding = hIC->hdr.decoding;
WININET_AddRef( &hIC->hdr );
session->appInfo = hIC;