static int winhttp_stream_write_single( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { winhttp_stream *s = (winhttp_stream *)stream; DWORD bytes_written; int error; if (!s->request && winhttp_stream_connect(s) < 0) return -1; /* This implementation of write permits only a single call. */ if (s->sent_request) { giterr_set(GITERR_NET, "Subtransport configured for only one write"); return -1; } if ((error = send_request(s, len, 0)) < 0) return error; s->sent_request = 1; if (!WinHttpWriteData(s->request, (LPCVOID)buffer, (DWORD)len, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write data"); return -1; } assert((DWORD)len == bytes_written); return 0; }
static int write_chunk(HINTERNET request, const char *buffer, size_t len) { DWORD bytes_written; git_buf buf = GIT_BUF_INIT; /* Chunk header */ git_buf_printf(&buf, "%X\r\n", len); if (git_buf_oom(&buf)) return -1; if (!WinHttpWriteData(request, git_buf_cstr(&buf), (DWORD)git_buf_len(&buf), &bytes_written)) { git_buf_free(&buf); giterr_set(GITERR_OS, "Failed to write chunk header"); return -1; } git_buf_free(&buf); /* Chunk body */ if (!WinHttpWriteData(request, buffer, (DWORD)len, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write chunk"); return -1; } /* Chunk footer */ if (!WinHttpWriteData(request, "\r\n", 2, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write chunk footer"); return -1; } return 0; }
static int winhttp_stream_write_single( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { winhttp_stream *s = (winhttp_stream *)stream; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); DWORD bytes_written; if (!s->request && winhttp_stream_connect(s) < 0) return -1; /* This implementation of write permits only a single call. */ if (s->sent_request) { giterr_set(GITERR_NET, "Subtransport configured for only one write"); return -1; } if (!WinHttpSendRequest(s->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, (DWORD)len, 0)) { giterr_set(GITERR_OS, "Failed to send request"); return -1; } s->sent_request = 1; if (!WinHttpWriteData(s->request, (LPCVOID)buffer, (DWORD)len, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write data"); return -1; } assert((DWORD)len == bytes_written); return 0; }
bool CWinHttp::PostDataToServer(PVOID pBuffer,int len) { bool bRet=false; DWORD dwBytesWritten=0; int index=0; while(1) { if( !WinHttpWriteData( hRequest, pBuffer, index, &dwBytesWritten) ) goto exit0; if(index==len) break; pBuffer=(PVOID)((DWORD)pBuffer+dwBytesWritten); index+=dwBytesWritten; } bRet=true; exit0: assert(bRet!=false); return bRet; }
// handle WinHTTP callbacks (which can be in a worker thread context) VOID CALLBACK WinHttpIO::asynccallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength) { WinHttpContext* httpctx = (WinHttpContext*)dwContext; WinHttpIO* httpio = (WinHttpIO*)httpctx->httpio; if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) { LOG_verbose << "Closing request"; assert(!httpctx->req); if (httpctx->gzip) { inflateEnd(&httpctx->z); } delete httpctx; return; } httpio->lock(); HttpReq* req = httpctx->req; // request cancellations that occured after asynccallback() was entered are caught here if (!req) { LOG_verbose << "Request cancelled"; httpio->unlock(); return; } switch (dwInternetStatus) { case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: { DWORD size = *(DWORD*)lpvStatusInformation; if (!size) { if (req->binary) { LOG_debug << "[received " << (req->buf ? req->buflen : req->in.size()) << " bytes of raw data]"; } else { if(req->in.size() < 2048) { LOG_debug << "Received: " << req->in.c_str(); } else { LOG_debug << "Received: " << req->in.substr(0,2048).c_str(); } } LOG_debug << "Request finished with HTTP status: " << req->httpstatus; req->status = (req->httpstatus == 200 && (req->contentlength < 0 || req->contentlength == (req->buf ? req->bufpos : (int)req->in.size()))) ? REQ_SUCCESS : REQ_FAILURE; if (req->status == REQ_SUCCESS) { httpio->lastdata = Waiter::ds; } httpio->success = true; } else { LOG_verbose << "Data available. Remaining: " << size << " bytes"; char* ptr; if (httpctx->gzip) { m_off_t zprevsize = httpctx->zin.size(); httpctx->zin.resize(zprevsize + size); ptr = (char*)httpctx->zin.data() + zprevsize; } else { ptr = (char*)req->reserveput((unsigned*)&size); req->bufpos += size; } if (!WinHttpReadData(hInternet, ptr, size, NULL)) { LOG_err << "Unable to get more data. Code: " << GetLastError(); httpio->cancel(req); } } httpio->httpevent(); break; } case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: LOG_verbose << "Read complete"; if (dwStatusInformationLength) { LOG_verbose << dwStatusInformationLength << " bytes received"; if (req->httpio) { req->httpio->lastdata = Waiter::ds; } if (httpctx->gzip) { httpctx->z.next_in = (Bytef*)lpvStatusInformation; httpctx->z.avail_in = dwStatusInformationLength; req->bufpos += httpctx->z.avail_out; int t = inflate(&httpctx->z, Z_SYNC_FLUSH); req->bufpos -= httpctx->z.avail_out; if ((char*)lpvStatusInformation + dwStatusInformationLength == httpctx->zin.data() + httpctx->zin.size()) { httpctx->zin.clear(); } if (t != Z_OK && (t != Z_STREAM_END || httpctx->z.avail_out)) { LOG_err << "GZIP error"; httpio->cancel(req); } } if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL)) { LOG_err << "Error on WinHttpQueryDataAvailable. Code: " << GetLastError(); httpio->cancel(req); httpio->httpevent(); } } break; case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: { DWORD statusCode; DWORD statusCodeSize = sizeof(statusCode); if (!WinHttpQueryHeaders(httpctx->hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) { LOG_err << "Error getting headers. Code: " << GetLastError(); httpio->cancel(req); httpio->httpevent(); } else { LOG_verbose << "Headers available"; req->httpstatus = statusCode; if (req->httpio) { req->httpio->lastdata = Waiter::ds; } if (!req->buf) { // obtain original content length - always present if gzip is in use DWORD contentLength; DWORD contentLengthSize = sizeof(contentLength); if (WinHttpQueryHeaders(httpctx->hRequest, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_NUMBER, L"Original-Content-Length", &contentLength, &contentLengthSize, WINHTTP_NO_HEADER_INDEX)) { LOG_verbose << "Content-Length: " << contentLength; req->setcontentlength(contentLength); // check for gzip content encoding WCHAR contentEncoding[16]; DWORD contentEncodingSize = sizeof(contentEncoding); httpctx->gzip = WinHttpQueryHeaders(httpctx->hRequest, WINHTTP_QUERY_CONTENT_ENCODING, WINHTTP_HEADER_NAME_BY_INDEX, &contentEncoding, &contentEncodingSize, WINHTTP_NO_HEADER_INDEX) && !wcscmp(contentEncoding, L"gzip"); if (httpctx->gzip) { LOG_verbose << "Using GZIP"; httpctx->z.zalloc = Z_NULL; httpctx->z.zfree = Z_NULL; httpctx->z.opaque = Z_NULL; httpctx->z.avail_in = 0; httpctx->z.next_in = Z_NULL; inflateInit2(&httpctx->z, MAX_WBITS+16); req->in.resize(contentLength); httpctx->z.avail_out = contentLength; httpctx->z.next_out = (unsigned char*)req->in.data(); } else { LOG_verbose << "Not using GZIP"; } } else { LOG_verbose << "Content-Length not available"; } } if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL)) { LOG_err << "Unable to query data. Code: " << GetLastError(); httpio->cancel(req); httpio->httpevent(); } else if (httpio->waiter && httpio->noinetds) { httpio->inetstatus(true); } } break; } case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: { DWORD e = GetLastError(); LOG_err << "Request error. Code: " << e; if (httpio->waiter && e != ERROR_WINHTTP_TIMEOUT) { httpio->inetstatus(false); } } // fall through case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) { LOG_err << "Security check failed. Code: " << (*(DWORD*)lpvStatusInformation); } httpio->cancel(req); httpio->httpevent(); break; case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: { if(MegaClient::disablepkp) { break; } PCCERT_CONTEXT cert; DWORD len = sizeof cert; if (WinHttpQueryOption(httpctx->hRequest, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert, &len)) { CRYPT_BIT_BLOB* pkey = &cert->pCertInfo->SubjectPublicKeyInfo.PublicKey; // this is an SSL connection: verify public key to prevent MITM attacks if (pkey->cbData != 270 || (memcmp(pkey->pbData, "\x30\x82\x01\x0a\x02\x82\x01\x01\x00" APISSLMODULUS1 "\x02" APISSLEXPONENTSIZE APISSLEXPONENT, 270) && memcmp(pkey->pbData, "\x30\x82\x01\x0a\x02\x82\x01\x01\x00" APISSLMODULUS2 "\x02" APISSLEXPONENTSIZE APISSLEXPONENT, 270))) { LOG_err << "Certificate error. Possible MITM attack!!"; CertFreeCertificateContext(cert); httpio->cancel(req); httpio->httpevent(); break; } CertFreeCertificateContext(cert); } break; } case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: if (httpctx->postpos < httpctx->postlen) { LOG_verbose << "Chunk written"; unsigned pos = httpctx->postpos; unsigned t = httpctx->postlen - pos; if (t > HTTP_POST_CHUNK_SIZE) { t = HTTP_POST_CHUNK_SIZE; } httpctx->postpos += t; if (!WinHttpWriteData(httpctx->hRequest, (LPVOID)(httpctx->postdata + pos), t, NULL)) { LOG_err << "Error writting data. Code: " << GetLastError(); req->httpio->cancel(req); } httpio->httpevent(); } else { LOG_verbose << "Request written"; if (!WinHttpReceiveResponse(httpctx->hRequest, NULL)) { LOG_err << "Error receiving response. Code: " << GetLastError(); httpio->cancel(req); httpio->httpevent(); } httpctx->postdata = NULL; } } httpio->unlock(); }
static int winhttp_stream_read( git_smart_subtransport_stream *stream, char *buffer, size_t buf_size, size_t *bytes_read) { winhttp_stream *s = (winhttp_stream *)stream; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); DWORD dw_bytes_read; char replay_count = 0; int error; replay: /* Enforce a reasonable cap on the number of replays */ if (++replay_count >= 7) { giterr_set(GITERR_NET, "Too many redirects or authentication replays"); return -1; } /* Connect if necessary */ if (!s->request && winhttp_stream_connect(s) < 0) return -1; if (!s->received_response) { DWORD status_code, status_code_length, content_type_length, bytes_written; char expected_content_type_8[MAX_CONTENT_TYPE_LEN]; wchar_t expected_content_type[MAX_CONTENT_TYPE_LEN], content_type[MAX_CONTENT_TYPE_LEN]; if (!s->sent_request) { if ((error = send_request(s, s->post_body_len, 0)) < 0) return error; s->sent_request = 1; } if (s->chunked) { assert(s->verb == post_verb); /* Flush, if necessary */ if (s->chunk_buffer_len > 0 && write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; /* Write the final chunk. */ if (!WinHttpWriteData(s->request, "0\r\n\r\n", 5, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write final chunk"); return -1; } } else if (s->post_body) { char *buffer; DWORD len = s->post_body_len, bytes_read; if (INVALID_SET_FILE_POINTER == SetFilePointer(s->post_body, 0, 0, FILE_BEGIN) && NO_ERROR != GetLastError()) { giterr_set(GITERR_OS, "Failed to reset file pointer"); return -1; } buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE); while (len > 0) { DWORD bytes_written; if (!ReadFile(s->post_body, buffer, min(CACHED_POST_BODY_BUF_SIZE, len), &bytes_read, NULL) || !bytes_read) { git__free(buffer); giterr_set(GITERR_OS, "Failed to read from temp file"); return -1; } if (!WinHttpWriteData(s->request, buffer, bytes_read, &bytes_written)) { git__free(buffer); giterr_set(GITERR_OS, "Failed to write data"); return -1; } len -= bytes_read; assert(bytes_read == bytes_written); } git__free(buffer); /* Eagerly close the temp file */ CloseHandle(s->post_body); s->post_body = NULL; } if (!WinHttpReceiveResponse(s->request, 0)) { giterr_set(GITERR_OS, "Failed to receive response"); return -1; } /* Verify that we got a 200 back */ status_code_length = sizeof(status_code); if (!WinHttpQueryHeaders(s->request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status_code, &status_code_length, WINHTTP_NO_HEADER_INDEX)) { giterr_set(GITERR_OS, "Failed to retrieve status code"); return -1; } /* The implementation of WinHTTP prior to Windows 7 will not * redirect to an identical URI. Some Git hosters use self-redirects * as part of their DoS mitigation strategy. Check first to see if we * have a redirect status code, and that we haven't already streamed * a post body. (We can't replay a streamed POST.) */ if (!s->chunked && (HTTP_STATUS_MOVED == status_code || HTTP_STATUS_REDIRECT == status_code || (HTTP_STATUS_REDIRECT_METHOD == status_code && get_verb == s->verb) || HTTP_STATUS_REDIRECT_KEEP_VERB == status_code)) { /* Check for Windows 7. This workaround is only necessary on * Windows Vista and earlier. Windows 7 is version 6.1. */ wchar_t *location; DWORD location_length; char *location8; /* OK, fetch the Location header from the redirect. */ if (WinHttpQueryHeaders(s->request, WINHTTP_QUERY_LOCATION, WINHTTP_HEADER_NAME_BY_INDEX, WINHTTP_NO_OUTPUT_BUFFER, &location_length, WINHTTP_NO_HEADER_INDEX) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { giterr_set(GITERR_OS, "Failed to read Location header"); return -1; } location = git__malloc(location_length); GITERR_CHECK_ALLOC(location); if (!WinHttpQueryHeaders(s->request, WINHTTP_QUERY_LOCATION, WINHTTP_HEADER_NAME_BY_INDEX, location, &location_length, WINHTTP_NO_HEADER_INDEX)) { giterr_set(GITERR_OS, "Failed to read Location header"); git__free(location); return -1; } /* Convert the Location header to UTF-8 */ if (git__utf16_to_8_alloc(&location8, location) < 0) { giterr_set(GITERR_OS, "Failed to convert Location header to UTF-8"); git__free(location); return -1; } git__free(location); /* Replay the request */ winhttp_stream_close(s); if (!git__prefixcmp_icase(location8, prefix_https)) { /* Upgrade to secure connection; disconnect and start over */ if (gitno_connection_data_from_url(&t->connection_data, location8, s->service_url) < 0) { git__free(location8); return -1; } winhttp_close_connection(t); if (winhttp_connect(t) < 0) return -1; } git__free(location8); goto replay; } /* Handle authentication failures */ if (HTTP_STATUS_DENIED == status_code && get_verb == s->verb) { int allowed_types; if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0) return -1; if (allowed_types && (!t->cred || 0 == (t->cred->credtype & allowed_types))) { int cred_error = 1; /* Start with the user-supplied credential callback, if present */ if (t->owner->cred_acquire_cb) { cred_error = t->owner->cred_acquire_cb(&t->cred, t->owner->url, t->connection_data.user, allowed_types, t->owner->cred_acquire_payload); if (cred_error < 0) return cred_error; } /* Invoke the fallback credentials acquisition callback if necessary */ if (cred_error > 0) { cred_error = fallback_cred_acquire_cb(&t->cred, t->owner->url, t->connection_data.user, allowed_types, NULL); if (cred_error < 0) return cred_error; } if (!cred_error) { assert(t->cred); winhttp_stream_close(s); /* Successfully acquired a credential */ goto replay; } } } if (HTTP_STATUS_OK != status_code) { giterr_set(GITERR_NET, "Request failed with status code: %d", status_code); return -1; } /* Verify that we got the correct content-type back */ if (post_verb == s->verb) p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-result", s->service); else p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service); if (git__utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) { giterr_set(GITERR_OS, "Failed to convert expected content-type to wide characters"); return -1; } content_type_length = sizeof(content_type); if (!WinHttpQueryHeaders(s->request, WINHTTP_QUERY_CONTENT_TYPE, WINHTTP_HEADER_NAME_BY_INDEX, &content_type, &content_type_length, WINHTTP_NO_HEADER_INDEX)) { giterr_set(GITERR_OS, "Failed to retrieve response content-type"); return -1; } if (wcscmp(expected_content_type, content_type)) { giterr_set(GITERR_NET, "Received unexpected content-type"); return -1; } s->received_response = 1; } if (!WinHttpReadData(s->request, (LPVOID)buffer, (DWORD)buf_size, &dw_bytes_read)) { giterr_set(GITERR_OS, "Failed to read data"); return -1; } *bytes_read = dw_bytes_read; return 0; }
UINT CWinHTTPUtil::UploadThread(LPVOID pParam) { if( pParam == NULL ){ return 0; } CWinHTTPUtil* sys = (CWinHTTPUtil*)pParam; HANDLE eventArray[2]; eventArray[0] = sys->upStopEvent; eventArray[1] = sys->writeCompEvent; SetEvent(sys->writeCompEvent); for( size_t i=0; i<sys->upDataList.size(); i++ ){ UPLOAD_DATA* data = sys->upDataList[i]; if( data->filePathFlag == FALSE ){ DWORD res = WaitForMultipleObjects(2, eventArray, FALSE, INFINITE); if( res == WAIT_OBJECT_0 ){ //STOP break; }else if( res == WAIT_OBJECT_0+1 ){ WinHttpWriteData( sys->request, data->buff, data->buffSize, NULL ); } }else{ HANDLE file; file = CreateFile( (WCHAR*)data->buff, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( file == INVALID_HANDLE_VALUE ){ sys->errEndCode = ERR_NW_FILE_OPEN; WinHttpSetStatusCallback( sys->request, NULL, NULL, NULL ); SetEvent(sys->responseCompEvent); return 0; } DWORD readSize = 0; DWORD readBuffSize = 0; BYTE buff[SEND_BUFF_SIZE]; DWORD fileSize = GetFileSize(file, NULL); while( readSize < fileSize ){ DWORD res = WaitForMultipleObjects(2, eventArray, FALSE, INFINITE); if( res == WAIT_OBJECT_0 ){ //STOP break; }else if( res == WAIT_OBJECT_0+1 ){ DWORD buffSize = 0; if( SEND_BUFF_SIZE+readSize < fileSize ){ buffSize = SEND_BUFF_SIZE; }else{ buffSize = fileSize - readSize; } if( ReadFile(file, buff, SEND_BUFF_SIZE, &readBuffSize, NULL ) == FALSE ){ sys->errEndCode = ERR_NW_FILE_OPEN; WinHttpSetStatusCallback( sys->request, NULL, NULL, NULL ); SetEvent(sys->responseCompEvent); return 0; }else{ DWORD retryCount = 0; while( WinHttpWriteData( sys->request, buff, readBuffSize, NULL ) == FALSE ){ Sleep(200); if( retryCount > 100 ){ sys->errEndCode = ERR_NW_FALSE; WinHttpSetStatusCallback( sys->request, NULL, NULL, NULL ); SetEvent(sys->responseCompEvent); return 0; } retryCount++; } } readSize+=buffSize; } } CloseHandle(file); } } WinHttpReceiveResponse(sys->request, NULL); sys->ClearUpList(); return 0; }
void WinHttpIO::_ProcessIO(HttpReq* req, WinHttpContext* cpContext) { enum ProcessStep { kStepStart, kStepSendRequest, kStepWriteData, kStepReceiveResponse, kStepQueryHeaders, kStepDataRead, kStepFinish, }; ProcessStep step = kStepStart; LPVOID data; DWORD size; if (cpContext->data.length()) { data = (LPVOID)cpContext->data.data(); size = (DWORD)cpContext->data.size(); } else { data = (LPVOID)req->out->data(); size = (DWORD)req->out->size(); } try { while (cpContext->bCancel == false) { BOOL bRet = FALSE; switch (step) { case kStepStart: step = kStepSendRequest; break; case kStepSendRequest: { LPCWSTR pwszHeaders = REQ_JSON ? L"Content-Type: application/json" : L"Content-Type: application/octet-stream"; bRet = WinHttpSendRequest(cpContext->hRequest, pwszHeaders, wcslen(pwszHeaders), WINHTTP_NO_REQUEST_DATA, 0, size, NULL); if (bRet == FALSE) throw std::exception("WinHttpSendRequest failed"); if (size == 0) { step = kStepReceiveResponse; } else { step = kStepWriteData; } } break; case kStepWriteData: { enum { kChunkSize = 32000 }; // 32kb LPCVOID buffPos = static_cast<BYTE*>(data) + cpContext->postpos; DWORD dwBytesWritten = 0; DWORD dwBuffSize = kChunkSize; DWORD restSize = size - cpContext->postpos; if (restSize < kChunkSize) dwBuffSize = restSize; bRet = WinHttpWriteData(cpContext->hRequest, buffPos, dwBuffSize, &dwBytesWritten); if (bRet == FALSE) throw std::exception("WinHttpWriteData failed"); cpContext->postpos += dwBytesWritten; if (cpContext->postpos == size) step = kStepReceiveResponse; } break; case kStepReceiveResponse: { bRet = ::WinHttpReceiveResponse(cpContext->hRequest, NULL); if (bRet == FALSE) { DWORD error = GetLastError(); throw std::exception("WinHttpReceiveResponse failed"); } step = kStepQueryHeaders; } break; case kStepQueryHeaders: { // ステータスコードを調べる DWORD statusCode = 0; DWORD statusCodeSize = sizeof(statusCode); bRet = ::WinHttpQueryHeaders(cpContext->hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX); if (bRet == FALSE) throw std::exception("WinHttpQueryHeaders failed"); req->httpstatus = (int)statusCode; step = kStepDataRead; } break; case kStepDataRead: { DWORD dwAvailableSize = 0; if (::WinHttpQueryDataAvailable(cpContext->hRequest, &dwAvailableSize) == FALSE) throw std::exception("WinHttpQueryDataAvailable failed"); if (dwAvailableSize == 0) { // もうデータがない step = kStepFinish; break; } unsigned size = (unsigned)dwAvailableSize; byte* buff = req->reserveput(&size); DWORD dwDownloaded = 0; bRet = ::WinHttpReadData(cpContext->hRequest, buff, size, &dwDownloaded); if (bRet == FALSE) throw std::exception("WinHttpReadData failed"); ATLASSERT(size == dwDownloaded); req->completeput((unsigned)dwDownloaded); } break; case kStepFinish: { req->status = req->httpstatus == 200 ? REQ_SUCCESS : REQ_FAILURE; return; } } } } catch (std::exception& e) { cout << e.what() << endl; } req->status = REQ_FAILURE; }