STDMETHODIMP WBPassthruSink::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR* pszAdditionalHeaders) { if (!szURL) { return E_POINTER; } std::wstring src = szURL; UnescapeUrl(src); DEBUG_GENERAL(src); std::string acceptHeader = ExtractHttpAcceptHeader(m_spTargetProtocol); if (pszAdditionalHeaders) { *pszAdditionalHeaders = nullptr; } CComPtr<IHttpNegotiate> httpNegotiate; QueryServiceFromClient(&httpNegotiate); // This fills the pszAdditionalHeaders with more headers. One of which is the Referer header, which we need. // There doesn't seem to be any other way to get this header before the request has been made. HRESULT nativeHr = httpNegotiate ? httpNegotiate->BeginningTransaction(szURL, szHeaders, dwReserved, pszAdditionalHeaders) : S_OK; if (pszAdditionalHeaders && *pszAdditionalHeaders) { m_boundDomain = ExtractHttpHeader<std::wstring>(*pszAdditionalHeaders, L"Referer:", L"\n"); } m_boundDomain = TrimString(m_boundDomain); m_contentType = GetContentType(ATL::CString(acceptHeader.c_str()), m_boundDomain, src); CPluginTab* tab = CPluginClass::GetTab(::GetCurrentThreadId()); CPluginClient* client = CPluginClient::GetInstance(); if (tab && client) { std::wstring documentUrl = tab->GetDocumentUrl(); // Page is identical to document => don't block if (documentUrl == src) { return nativeHr; } else if (CPluginSettings::GetInstance()->IsPluginEnabled() && !client->IsWhitelistedUrl(documentUrl)) { if (tab->IsFrameCached(src)) { m_contentType = ContentType::CONTENT_TYPE_SUBDOCUMENT; } } } if (IsFlashRequest(pszAdditionalHeaders)) { m_contentType = ContentType::CONTENT_TYPE_OBJECT_SUBREQUEST; } if (pszAdditionalHeaders && *pszAdditionalHeaders && IsXmlHttpRequest(*pszAdditionalHeaders)) { m_contentType = ContentType::CONTENT_TYPE_XMLHTTPREQUEST; } if (client->ShouldBlock(szURL, m_contentType, m_boundDomain, /*debug flag but must be set*/true)) { // NOTE: Feeding custom HTML to Flash, instead of original object subrequest // doesn't have much sense. It also can manifest in unwanted result // like video being blocked (See https://issues.adblockplus.org/ticket/1669) // So we report blocked object subrequests as failed, not just empty HTML. m_isCustomResponse = m_contentType != ContentType::CONTENT_TYPE_OBJECT_SUBREQUEST; return E_ABORT; } return nativeHr; }
bool CreatorHTTP_Call(CreatorMemoryManager memoryManager, CreatorHTTPMethod httpMethod, char *url, CreatorType expectedType, CreatorObject *pResponse, CreatorObject bodyData, CreatorHTTPStatus *status) { bool result = false; CreatorThread_ClearLastError(); if (pResponse) *pResponse = NULL; url = UnescapeUrl(url); if (memoryManager && url) { if (httpMethod == CreatorHTTPMethod_Get) { CreatorObject cachedValue = CreatorCache_Get(url); if (cachedValue) { if (pResponse) { *pResponse = CreatorXMLDeserialiser_NewObject(expectedType); CreatorObject_CopyFrom(*pResponse, cachedValue); if (*pResponse) { CreatorMemoryManager_AttachObject(memoryManager, *pResponse); //CreatorObject_SetJob(*pResponse,memoryManager); } } if (status) { *status = CreatorHTTPStatus_OK; //Return HTTP status 200 if found in cache. } Creator_MemFree((void **)&url); return true; } } CreatorHTTPMethod actualMethod = httpMethod; //use X-HTTP-Method-Override if (httpMethod == CreatorHTTPMethod_Put || httpMethod == CreatorHTTPMethod_Delete) { httpMethod = CreatorHTTPMethod_Post; } //prepare context for HTTP call HTTPCallbackContext httpContext; memset(&httpContext, 0, sizeof(httpContext)); httpContext.MemoryManager = memoryManager; httpContext.Success = true; httpContext.Semaphore = CreatorSemaphore_New(1, 1); httpContext.ExpectedType = expectedType; httpContext.ResponseType = CreatorType__Unknown; httpContext.IsSuccessResponse = false; httpContext.IsBadRequestResponse = false; httpContext.HasParserError = false; httpContext.Expires = 0; httpContext.Status = CreatorHTTPStatus_NotSet; httpContext.Error = CreatorError_NoError; httpContext.Request = CreatorHTTPRequest_New(actualMethod, url, ResultCallback, HeaderCallback, DataCallback, FinishCallback, &httpContext); if (httpContext.Semaphore && httpContext.Request) { Creator_Log(CreatorLogLevel_Debug, "HTTP %p will handle %s %s", httpContext.Request, CreatorHTTPMethod_ToString(httpMethod), url); //add X-HTTP-Method-Override if (httpMethod != actualMethod) { CreatorHTTPRequest_AddHeader(httpContext.Request, "X-HTTP-Method-Override", CreatorHTTPMethod_ToString(httpMethod)); } const char *locale = CreatorClient_GetLocale(); if (locale && strlen(locale)) { CreatorHTTPRequest_AddHeader(httpContext.Request, "X-Culture", locale); } const char *bodyContentType = CreatorClient_GetBodyContentType(); if (bodyContentType && strlen(bodyContentType)) { if (!strstr(bodyContentType, "xml")) { CreatorHTTPRequest_AddHeader(httpContext.Request, "X-Body-Content-Type", bodyContentType); } } char requestId[65]; snprintf(requestId, sizeof(requestId), "%lX", (unsigned long)httpContext.Request); CreatorHTTPRequest_AddHeader(httpContext.Request, "X-Client-RequestId", requestId); /* ??? TODO add Accept-Language ??? */ //set up oAuth authorization CreatorHTTP_AddAuthorizationHeader(memoryManager, httpContext.Request, actualMethod, url); //add accept header const char *mimes[4] = { (httpContext.ExpectedType != CreatorType__Unknown) ? CreatorXMLDeserialiser_GetMIMEType(httpContext.ExpectedType) : "", CreatorXMLDeserialiser_GetMIMEType(CreatorType_Error), CreatorXMLDeserialiser_GetMIMEType(CreatorType_BadRequestResponse), "*/*" }; char *acceptedMimeTypes = ConcatenateAcceptValues(mimes, sizeof(mimes) / sizeof(*mimes), "+xml"); if (acceptedMimeTypes) { CreatorHTTPRequest_AddHeader(httpContext.Request, "Accept", acceptedMimeTypes); Creator_MemFree((void **)&acceptedMimeTypes); } if (httpContext.ExpectedType != CreatorType__Unknown) Creator_MemFree((void **)&mimes[0]); Creator_MemFree((void **)&mimes[1]); Creator_MemFree((void **)&mimes[2]); /* handle body */ if (bodyData) { Creator_Assert(actualMethod != CreatorHTTPMethod_Get, "HTTP %p: GET does not allow a request body", httpContext.Request); // Note: some HTTP libs need all headers to be set before the data char contentType[256]; char *mimeType = CreatorXMLDeserialiser_GetMIMEType(CreatorObject_GetType(bodyData)); strncpy(contentType, mimeType, sizeof(contentType)); Creator_MemFree((void **)&mimeType); strcat(contentType, "+xml"); CreatorHTTPRequest_AddHeader(httpContext.Request, "Content-Type", contentType); int bodySize = 0; char *body = CreatorObject_SerialiseToXML(bodyData, &bodySize); if (body) { CreatorHTTPRequest_SetBody(httpContext.Request, body, bodySize); Creator_MemFree((void **)&body); } } if (CreatorThread_GetLastError() == CreatorError_NoError) { int attemptCount = 0; do { httpContext.Error = CreatorError_NoError; CreatorHTTPRequest_Send(httpContext.Request); /* wait for lock availability (data received and parsed) */ CreatorSemaphore_Wait(httpContext.Semaphore, 1); attemptCount += 1; } while ((attemptCount < 2) && (httpContext.Error == CreatorError_Network)); if (httpContext.Error != CreatorError_NoError) CreatorThread_SetError(httpContext.Error); } if (httpContext.IsSuccessResponse && !httpContext.HasParserError) { Creator_Log(CreatorLogLevel_Info, "HTTP %s %s response %u", CreatorHTTPMethod_ToString(httpMethod), url, httpContext.Status); } if (httpContext.Deserialiser) { CreatorObject response = CreatorXMLDeserialiser_GetObject(httpContext.Deserialiser); if (response) { if ((httpMethod == CreatorHTTPMethod_Get) && (httpContext.ResponseType == httpContext.ExpectedType)) { CreatorXMLDeserialiser_SetSelfLink(httpContext.Deserialiser, response, url); } CreatorMemoryManager_AttachObject(memoryManager, response); } if (pResponse) { *pResponse = response; } CreatorXMLDeserialiser_Free(&httpContext.Deserialiser); } //notify cache manager of the result if (httpContext.IsSuccessResponse && !httpContext.HasParserError) { if ((httpMethod == CreatorHTTPMethod_Get) && CreatorThread_GetUseOAuth()) { if ((httpContext.ResponseType == httpContext.ExpectedType) && (httpContext.Expires > 0)) { if (pResponse) CreatorCache_Set(url, *pResponse, httpContext.Expires); } } } if (!httpContext.IsSuccessResponse) { if (!httpContext.HasParserError && httpContext.ResponseType == CreatorType_BadRequestResponse) { if (pResponse) { CreatorBadRequestResponse errorResponse = (CreatorBadRequestResponse) * pResponse; int errorCode = CreatorBadRequestResponse_GetErrorCode(errorResponse); CreatorErrorType errorType = ((errorCode - 1 + (int)CreatorError_BadRequest_Min >= CreatorError_BadRequest_Unknown) || (errorCode <= 0)) ? CreatorError_BadRequest_Unknown : (CreatorErrorType)(errorCode - 1 + (int)CreatorError_BadRequest_Min); CreatorThread_SetError(errorType); Creator_Log(CreatorLogLevel_Error, "HTTP %s %s response %u - failed with [%d]", CreatorHTTPMethod_ToString(httpMethod), url, httpContext.Status, errorType); } else { CreatorThread_SetError(CreatorError_BadRequest_Unknown); } } else if (httpContext.Error == CreatorError_Server) { Creator_Log(CreatorLogLevel_Error, "HTTP %s %s response %u - failed (internal server error)", CreatorHTTPMethod_ToString(httpMethod), url, httpContext.Status); } else { Creator_Log(CreatorLogLevel_Error, "HTTP %s %s response %u - failed (no content returned)", CreatorHTTPMethod_ToString(httpMethod), url, httpContext.Status); if (CreatorThread_GetLastError() == CreatorError_NoError) { CreatorThread_SetError((httpContext.IsBadRequestResponse) ? CreatorError_BadRequest_Unknown : CreatorError_InvalidArgument); } httpContext.Success = false; } } } else { /* error */ //Creator_Log(CreatorLogLevel_Error, "HTTP %p (%s %s) failed to start: parser instance %p, semaphore %p", httpContext.Request, CreatorHTTPMethod_ToString(httpMethod), url, httpContext.parsingContext.parserInstance, httpContext.Semaphore); Creator_Log(CreatorLogLevel_Error, "HTTP %p (%s %s) failed to start", httpContext.Request, CreatorHTTPMethod_ToString(httpMethod), url); CreatorThread_SetError(CreatorError_Internal); httpContext.Success = false; } if (httpContext.Request) { CreatorHTTPRequest_Free(&httpContext.Request); } if (httpContext.Semaphore) { CreatorSemaphore_Free(&httpContext.Semaphore); } if (status) *status = httpContext.Status; result = httpContext.Success; } if (url) Creator_MemFree((void **)&url); return result; }