Chromium 中前端js XMLHttpRequest接口c++代码实现

在JavaScript中发出HTTP请求的主要方式包括:XMLHttpRequest对象、Fetch APIAxios库和各种其他的HTTP客户端库

本人主要分析下XMLHttpRequest接口在c++中对应实现

一、上前端代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Send HTTP Request</title>
<script>
function sendRequest() {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://192.168.8.1/chfs/shared/test/1.txt", true);
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
            // 请求成功
            alert(xhr.responseText);
        }
    };
    xhr.send();
}
</script>
</head>
<body>
 
<button onclick="sendRequest()">Send HTTP Request</button>
 
</body>
</html>

二、看c++代码实现

   1、XMLHttpRequest 接口定义在           third_party\blink\renderer\core\xmlhttprequest\xml_http_request.idl

  

/*
 * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// https://xhr.spec.whatwg.org/#interface-xmlhttprequest

enum XMLHttpRequestResponseType {
    "",
    "arraybuffer",
    "blob",
    "document",
    "json",
    "text",
};

// This is in fetch.idl in the standard, but for simplicity we define it here.
typedef (Blob or BufferSource or FormData or URLSearchParams or USVString) XMLHttpRequestBodyInit;

[
    ActiveScriptWrappable,
    Exposed=(Window,DedicatedWorker,SharedWorker)
] interface XMLHttpRequest : XMLHttpRequestEventTarget {
    [CallWith=ScriptState] constructor();
    // event handler
    attribute EventHandler onreadystatechange;

    // states
    const unsigned short UNSENT = 0;
    const unsigned short OPENED = 1;
    const unsigned short HEADERS_RECEIVED = 2;
    const unsigned short LOADING = 3;
    const unsigned short DONE = 4;
    readonly attribute unsigned short readyState;

    // request
    [RaisesException] void open(ByteString method, USVString url);
    [RaisesException] void open(ByteString method, USVString url, boolean async, optional USVString? username = null, optional USVString? password = null);
    [RaisesException] void setRequestHeader(ByteString name, ByteString value);
    [RaisesException, RuntimeEnabled=PrivateStateTokens, SecureContext, MeasureAs=TrustTokenXhr] void setPrivateToken(PrivateToken privateToken);
    [RaisesException, RuntimeEnabled=AttributionReportingInterface, SecureContext] void setAttributionReporting(AttributionReportingRequestOptions attributionReporting);
    [RaisesException=Setter] attribute unsigned long timeout;
    [RaisesException=Setter] attribute boolean withCredentials;
    readonly attribute XMLHttpRequestUpload upload;
    [RaisesException] void send(optional (Document or XMLHttpRequestBodyInit)? body = null);
    void abort();

    // response
    readonly attribute USVString responseURL;
    readonly attribute unsigned short status;
    readonly attribute ByteString statusText;
    ByteString? getResponseHeader(ByteString name);
    ByteString getAllResponseHeaders();
    [RaisesException] void overrideMimeType(DOMString mime);
    [RaisesException=Setter] attribute XMLHttpRequestResponseType responseType;
    [CallWith=ScriptState, RaisesException=Getter] readonly attribute any response;
    [RaisesException=Getter] readonly attribute USVString responseText;
    // TODO(foolip): responseXML should be [Exposed=Window].
    [MeasureAs=XMLHttpRequestResponseXML, RaisesException=Getter] readonly attribute Document? responseXML;
};

2、XMLHttpRequest 接口c++实现在xml_http_request.h中,如果想控制此接口可以在此更改具体实现。

third_party\blink\renderer\core\xmlhttprequest\xml_http_request.h

third_party\blink\renderer\core\xmlhttprequest\xml_http_request.cc

/*
 *  Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
 *  Copyright (C) 2005, 2006 Alexey Proskuryakov <ap@nypop.com>
 *  Copyright (C) 2011 Google Inc. All rights reserved.
 *  Copyright (C) 2012 Intel Corporation
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA 02110-1301 USA
 */

#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_XMLHTTPREQUEST_XML_HTTP_REQUEST_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_XMLHTTPREQUEST_XML_HTTP_REQUEST_H_

#include <memory>

#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/attribution.mojom-blink.h"
#include "services/network/public/mojom/trust_tokens.mojom-blink.h"
#include "services/network/public/mojom/url_loader_factory.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/document_parser_client.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
#include "third_party/blink/renderer/core/probe/async_task_context.h"
#include "third_party/blink/renderer/core/xmlhttprequest/xml_http_request_event_target.h"
#include "third_party/blink/renderer/core/xmlhttprequest/xml_http_request_progress_event_throttle.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
#include "third_party/blink/renderer/platform/network/http_header_map.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

class AttributionReportingRequestOptions;
class Blob;
class BlobDataHandle;
class DOMArrayBuffer;
class DOMArrayBufferView;
class DOMWrapperWorld;
class Document;
class DocumentParser;
class ExceptionState;
class ExecutionContext;
class FormData;
class PrivateToken;
class ScriptState;
class ScriptValue;
class TextResourceDecoder;
class ThreadableLoader;
class URLSearchParams;
class XMLHttpRequestUpload;

class CORE_EXPORT XMLHttpRequest final
    : public XMLHttpRequestEventTarget,
      public ThreadableLoaderClient,
      public DocumentParserClient,
      public ActiveScriptWrappable<XMLHttpRequest>,
      public ExecutionContextLifecycleObserver {
  DEFINE_WRAPPERTYPEINFO();

 public:
  static XMLHttpRequest* Create(ScriptState*);
  static XMLHttpRequest* Create(ExecutionContext*);

  XMLHttpRequest(ExecutionContext*, scoped_refptr<const DOMWrapperWorld> world);
  ~XMLHttpRequest() override;

  // These exact numeric values are important because JS expects them.
  enum State {
    kUnsent = 0,
    kOpened = 1,
    kHeadersReceived = 2,
    kLoading = 3,
    kDone = 4
  };

  enum ResponseTypeCode {
    kResponseTypeDefault,
    kResponseTypeText,
    kResponseTypeJSON,
    kResponseTypeDocument,
    kResponseTypeBlob,
    kResponseTypeArrayBuffer,
  };

  // ExecutionContextLifecycleObserver
  void ContextDestroyed() override;
  ExecutionContext* GetExecutionContext() const override;

  // ScriptWrappable
  bool HasPendingActivity() const final;

  // XMLHttpRequestEventTarget
  const AtomicString& InterfaceName() const override;

  // JavaScript attributes and methods
  const KURL& Url() const { return url_; }
  String statusText() const;
  int status() const;
  State readyState() const;
  bool withCredentials() const { return with_credentials_; }
  void setWithCredentials(bool, ExceptionState&);
  void open(const AtomicString& method, const String& url, ExceptionState&);
  void open(const AtomicString& method,
            const String& url,
            bool async,
            const String& username,
            const String& password,
            ExceptionState&);
  void open(const AtomicString& method,
            const KURL&,
            bool async,
            ExceptionState&);
  void send(const V8UnionDocumentOrXMLHttpRequestBodyInit* body,
            ExceptionState& exception_state);
  void abort();
  void Dispose();
  void setRequestHeader(const AtomicString& name,
                        const AtomicString& value,
                        ExceptionState&);
  void setPrivateToken(const PrivateToken*, ExceptionState&);
  void setAttributionReporting(const AttributionReportingRequestOptions*,
                               ExceptionState&);
  void overrideMimeType(const AtomicString& override, ExceptionState&);
  String getAllResponseHeaders() const;
  const AtomicString& getResponseHeader(const AtomicString&) const;
  String responseText(ExceptionState&);
  Document* responseXML(ExceptionState&);
  ScriptValue response(ScriptState*, ExceptionState&);
  unsigned timeout() const {
    return static_cast<unsigned>(timeout_.InMilliseconds());
  }
  void setTimeout(unsigned timeout, ExceptionState&);
  ResponseTypeCode GetResponseTypeCode() const { return response_type_code_; }
  String responseType();
  void setResponseType(const String&, ExceptionState&);
  String responseURL();

  // For Inspector.
  void SendForInspectorXHRReplay(scoped_refptr<EncodedFormData>,
                                 ExceptionState&);

  XMLHttpRequestUpload* upload();
  bool IsAsync() { return async_; }

  probe::AsyncTaskContext* async_task_context() { return &async_task_context_; }

  DEFINE_ATTRIBUTE_EVENT_LISTENER(readystatechange, kReadystatechange)

  void Trace(Visitor*) const override;
  const char* NameInHeapSnapshot() const override { return "XMLHttpRequest"; }

  bool HasRequestHeaderForTesting(AtomicString name) const;

 private:
  class BlobLoader;

  void DidSendData(uint64_t bytes_sent,
                   uint64_t total_bytes_to_be_sent) override;
  void DidReceiveResponse(uint64_t identifier,
                          const ResourceResponse&) override;
  void DidReceiveData(const char* data, unsigned data_length) override;
  // When responseType is set to "blob", didDownloadData() is called instead
  // of didReceiveData().
  void DidDownloadData(uint64_t data_length) override;
  void DidDownloadToBlob(scoped_refptr<BlobDataHandle>) override;
  void DidFinishLoading(uint64_t identifier) override;
  void DidFail(uint64_t, const ResourceError&) override;
  void DidFailRedirectCheck(uint64_t) override;

  // BlobLoader notifications.
  void DidFinishLoadingInternal();
  void DidFinishLoadingFromBlob();
  void DidFailLoadingFromBlob();

  // DocumentParserClient
  void NotifyParserStopped() override;

  void EndLoading();

  v8::Local<v8::Value> ResponseJSON(v8::Isolate*, ExceptionState&);
  Blob* ResponseBlob();
  DOMArrayBuffer* ResponseArrayBuffer();

  // Returns the MIME type part of mime_type_override_ if present and
  // successfully parsed, or returns one of the "Content-Type" header value
  // of the received response.
  //
  // This method is named after the term "final MIME type" defined in the
  // spec but doesn't convert the result to ASCII lowercase as specified in
  // the spec. Must be lowered later or compared using case insensitive
  // comparison functions if required.
  AtomicString FinalResponseMIMETypeInternal() const;
  // The same as finalResponseMIMEType() but fallbacks to "text/xml" if
  // finalResponseMIMEType() returns an empty string.
  // https://xhr.spec.whatwg.org/#response-body
  AtomicString GetResponseMIMEType() const;
  // Returns the "final charset" defined in
  // https://xhr.spec.whatwg.org/#final-charset.
  WTF::TextEncoding FinalResponseCharset() const;
  bool ResponseIsXML() const;
  bool ResponseIsHTML() const;

  std::unique_ptr<TextResourceDecoder> CreateDecoder() const;

  void InitResponseDocument();
  void ParseDocumentChunk(const char* data, unsigned data_length);

  bool AreMethodAndURLValidForSend();

  void ThrowForLoadFailureIfNeeded(ExceptionState&, const String&);

  bool InitSend(ExceptionState&);
  void SendBytesData(const void*, size_t, ExceptionState&);
  void send(Document*, ExceptionState&);
  void send(const String&, ExceptionState&);
  void send(Blob*, ExceptionState&);
  void send(FormData*, ExceptionState&);
  void send(URLSearchParams*, ExceptionState&);
  void send(DOMArrayBuffer*, ExceptionState&);
  void send(DOMArrayBufferView*, ExceptionState&);

  bool HasContentTypeRequestHeader() const;
  void SetRequestHeaderInternal(const AtomicString& name,
                                const AtomicString& value);

  void TrackProgress(uint64_t data_length);
  // Changes m_state and dispatches a readyStateChange event if new m_state
  // value is different from last one.
  void ChangeState(State new_state);
  void DispatchReadyStateChangeEvent();

  // Clears variables used only while the resource is being loaded.
  void ClearVariablesForLoading();
  // Clears state and cancels loader.
  void InternalAbort();
  // Clears variables holding response header and body data.
  void ClearResponse();
  void ClearRequest();

  void CreateRequest(scoped_refptr<EncodedFormData>, ExceptionState&);

  // Dispatches a response ProgressEvent.
  void DispatchProgressEvent(const AtomicString&, int64_t, int64_t);
  // Dispatches a response ProgressEvent using values sampled from
  // m_receivedLength and m_response.
  void DispatchProgressEventFromSnapshot(const AtomicString&);

  // Handles didFail() call not caused by cancellation or timeout.
  void HandleNetworkError();
  // Handles didFail() call for cancellations. For example, the
  // ResourceLoader handling the load notifies m_loader of an error
  // cancellation when the frame containing the XHR navigates away.
  void HandleDidCancel();
  // Handles didFail() call for timeout.
  void HandleDidTimeout();

  void HandleRequestError(DOMExceptionCode, const AtomicString&);

  void UpdateContentTypeAndCharset(const AtomicString& content_type,
                                   const String& charset);

  XMLHttpRequestProgressEventThrottle& ProgressEventThrottle();

  // Report the memory usage associated with this object to V8 so that V8 can
  // schedule GC accordingly.  This function should be called whenever the
  // internal memory usage changes except for the following members.
  // - response_array_buffer_ of type DOMArrayBuffer
  //   DOMArrayBuffer supports the memory usage reporting system on their own,
  //   so there is no need.
  void ReportMemoryUsageToV8();

  Member<XMLHttpRequestUpload> upload_;

  KURL url_;
  mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
      blob_url_loader_factory_;
  AtomicString method_;
  HTTPHeaderMap request_headers_;
  network::mojom::blink::TrustTokenParamsPtr trust_token_params_;
  // Not converted to ASCII lowercase. Must be lowered later or compared
  // using case insensitive comparison functions if needed.
  AtomicString mime_type_override_;
  base::TimeDelta timeout_;
  Member<Blob> response_blob_;

  TaskHandle pending_abort_event_;

  Member<ThreadableLoader> loader_;
  State state_ = kUnsent;

  ResourceResponse response_;

  std::unique_ptr<TextResourceDecoder> decoder_;

  StringBuilder response_text_;
  bool response_text_overflow_ = false;
  size_t response_text_last_reported_size_ = 0;
  Member<Document> response_document_;
  Member<DocumentParser> response_document_parser_;

  scoped_refptr<SharedBuffer> binary_response_builder_;
  size_t binary_response_builder_last_reported_size_ = 0;
  int64_t length_downloaded_to_blob_ = 0;
  int64_t length_downloaded_to_blob_last_reported_ = 0;

  Member<DOMArrayBuffer> response_array_buffer_;

  // Used for onprogress tracking
  int64_t received_length_ = 0;

  // An exception to throw in synchronous mode. It's set when failure
  // notification is received from m_loader and thrown at the end of send() if
  // any.
  DOMExceptionCode exception_code_ = DOMExceptionCode::kNoError;

  Member<XMLHttpRequestProgressEventThrottle> progress_event_throttle_;

  // An enum corresponding to the allowed string values for the responseType
  // attribute.
  ResponseTypeCode response_type_code_ = kResponseTypeDefault;

  // The DOMWrapperWorld in which the request initiated. Can be null.
  scoped_refptr<const DOMWrapperWorld> world_;
  // Stores the SecurityOrigin associated with the |world_| if it's an isolated
  // world.
  scoped_refptr<const SecurityOrigin> isolated_world_security_origin_;

  // This blob loader will be used if |m_downloadingToFile| is true and
  // |m_responseTypeCode| is NOT ResponseTypeBlob.
  Member<BlobLoader> blob_loader_;

  bool async_ = true;

  bool with_credentials_ = false;

  network::mojom::AttributionReportingEligibility
      attribution_reporting_eligibility_ =
          network::mojom::AttributionReportingEligibility::kUnset;

  // Used to skip m_responseDocument creation if it's done previously. We need
  // this separate flag since m_responseDocument can be 0 for some cases.
  bool parsed_response_ = false;
  bool error_ = false;
  bool upload_events_allowed_ = true;
  bool upload_complete_ = false;
  // True iff the ongoing resource loading is using the downloadToBlob
  // option.
  bool downloading_to_blob_ = false;
  bool send_flag_ = false;
  bool response_array_buffer_failure_ = false;

  probe::AsyncTaskContext async_task_context_;
};

std::ostream& operator<<(std::ostream&, const XMLHttpRequest*);

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_XMLHTTPREQUEST_XML_HTTP_REQUEST_H_

三、看下调试堆栈效果图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值