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;
}
Exemple #2
0
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;
}