| // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef NET_HTTP_HTTP_NETWORK_TRANSACTION_H_ |
| #define NET_HTTP_HTTP_NETWORK_TRANSACTION_H_ |
| |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/ref_counted.h" |
| #include "base/scoped_ptr.h" |
| #include "base/time.h" |
| #include "net/base/address_list.h" |
| #include "net/base/host_resolver.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/load_states.h" |
| #include "net/base/net_log.h" |
| #include "net/base/ssl_config_service.h" |
| #include "net/http/http_alternate_protocols.h" |
| #include "net/http/http_auth.h" |
| #include "net/http/http_auth_handler.h" |
| #include "net/http/http_response_info.h" |
| #include "net/http/http_transaction.h" |
| #include "net/proxy/proxy_service.h" |
| #include "net/socket/client_socket_pool.h" |
| #include "testing/gtest/include/gtest/gtest_prod.h" |
| |
| namespace net { |
| |
| class ClientSocketFactory; |
| class ClientSocketHandle; |
| class SpdyStream; |
| class HttpNetworkSession; |
| class HttpStream; |
| |
| class HttpNetworkTransaction : public HttpTransaction { |
| public: |
| explicit HttpNetworkTransaction(HttpNetworkSession* session); |
| |
| virtual ~HttpNetworkTransaction(); |
| |
| // Sets the next protocol negotiation value used during the SSL handshake. |
| static void SetNextProtos(const std::string& next_protos); |
| |
| // Sets the HttpNetworkTransaction into a mode where it can ignore |
| // certificate errors. This is for testing. |
| static void IgnoreCertificateErrors(bool enabled); |
| |
| // HttpTransaction methods: |
| virtual int Start(const HttpRequestInfo* request_info, |
| CompletionCallback* callback, |
| const BoundNetLog& net_log); |
| virtual int RestartIgnoringLastError(CompletionCallback* callback); |
| virtual int RestartWithCertificate(X509Certificate* client_cert, |
| CompletionCallback* callback); |
| virtual int RestartWithAuth(const std::wstring& username, |
| const std::wstring& password, |
| CompletionCallback* callback); |
| virtual bool IsReadyToRestartForAuth() { |
| return pending_auth_target_ != HttpAuth::AUTH_NONE && |
| HaveAuth(pending_auth_target_); |
| } |
| |
| virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); |
| virtual void StopCaching() {} |
| virtual const HttpResponseInfo* GetResponseInfo() const; |
| virtual LoadState GetLoadState() const; |
| virtual uint64 GetUploadProgress() const; |
| |
| private: |
| FRIEND_TEST(HttpNetworkTransactionTest, ResetStateForRestart); |
| |
| enum State { |
| STATE_RESOLVE_PROXY, |
| STATE_RESOLVE_PROXY_COMPLETE, |
| STATE_INIT_CONNECTION, |
| STATE_INIT_CONNECTION_COMPLETE, |
| STATE_SOCKS_CONNECT, |
| STATE_SOCKS_CONNECT_COMPLETE, |
| STATE_SSL_CONNECT, |
| STATE_SSL_CONNECT_COMPLETE, |
| STATE_SEND_REQUEST, |
| STATE_SEND_REQUEST_COMPLETE, |
| STATE_READ_HEADERS, |
| STATE_READ_HEADERS_COMPLETE, |
| STATE_READ_BODY, |
| STATE_READ_BODY_COMPLETE, |
| STATE_DRAIN_BODY_FOR_AUTH_RESTART, |
| STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE, |
| STATE_SPDY_SEND_REQUEST, |
| STATE_SPDY_SEND_REQUEST_COMPLETE, |
| STATE_SPDY_READ_HEADERS, |
| STATE_SPDY_READ_HEADERS_COMPLETE, |
| STATE_SPDY_READ_BODY, |
| STATE_SPDY_READ_BODY_COMPLETE, |
| STATE_NONE |
| }; |
| |
| enum ProxyMode { |
| kDirectConnection, // If using a direct connection |
| kHTTPProxy, // If using a proxy for HTTP (not HTTPS) |
| kHTTPProxyUsingTunnel, // If using a tunnel for HTTPS |
| kSOCKSProxy, // If using a SOCKS proxy |
| }; |
| |
| enum AlternateProtocolMode { |
| kUnspecified, // Unspecified, check HttpAlternateProtocols |
| kUsingAlternateProtocol, // Using an alternate protocol |
| kDoNotUseAlternateProtocol, // Failed to connect once, do not try again. |
| }; |
| |
| void DoCallback(int result); |
| void OnIOComplete(int result); |
| |
| // Runs the state transition loop. |
| int DoLoop(int result); |
| |
| // Each of these methods corresponds to a State value. Those with an input |
| // argument receive the result from the previous state. If a method returns |
| // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the |
| // next state method as the result arg. |
| int DoResolveProxy(); |
| int DoResolveProxyComplete(int result); |
| int DoInitConnection(); |
| int DoInitConnectionComplete(int result); |
| int DoSOCKSConnect(); |
| int DoSOCKSConnectComplete(int result); |
| int DoSSLConnect(); |
| int DoSSLConnectComplete(int result); |
| int DoSendRequest(); |
| int DoSendRequestComplete(int result); |
| int DoReadHeaders(); |
| int DoReadHeadersComplete(int result); |
| int DoReadBody(); |
| int DoReadBodyComplete(int result); |
| int DoDrainBodyForAuthRestart(); |
| int DoDrainBodyForAuthRestartComplete(int result); |
| int DoSpdySendRequest(); |
| int DoSpdySendRequestComplete(int result); |
| int DoSpdyReadHeaders(); |
| int DoSpdyReadHeadersComplete(int result); |
| int DoSpdyReadBody(); |
| int DoSpdyReadBodyComplete(int result); |
| |
| // Record histograms of latency until Connect() completes. |
| static void LogTCPConnectedMetrics(const ClientSocketHandle& handle); |
| |
| // Record histogram of time until first byte of header is received. |
| void LogTransactionConnectedMetrics() const; |
| |
| // Record histogram of latency (durations until last byte received). |
| void LogTransactionMetrics() const; |
| |
| // Writes a log message to help debugging in the field when we block a proxy |
| // response to a CONNECT request. |
| void LogBlockedTunnelResponse(int response_code) const; |
| |
| static void LogIOErrorMetrics(const ClientSocketHandle& handle); |
| |
| // Called to handle a certificate error. Returns OK if the error should be |
| // ignored. Otherwise, stores the certificate in response_.ssl_info and |
| // returns the same error code. |
| int HandleCertificateError(int error); |
| |
| // Called to handle a client certificate request. |
| int HandleCertificateRequest(int error); |
| |
| // Called to possibly recover from an SSL handshake error. Sets next_state_ |
| // and returns OK if recovering from the error. Otherwise, the same error |
| // code is returned. |
| int HandleSSLHandshakeError(int error); |
| |
| // Called to possibly recover from the given error. Sets next_state_ and |
| // returns OK if recovering from the error. Otherwise, the same error code |
| // is returned. |
| int HandleIOError(int error); |
| |
| // Gets the response headers from the HttpStream. |
| HttpResponseHeaders* GetResponseHeaders() const; |
| |
| // Called when we reached EOF or got an error. Returns true if we should |
| // resend the request. |error| is OK when we reached EOF. |
| bool ShouldResendRequest(int error) const; |
| |
| // Resets the connection and the request headers for resend. Called when |
| // ShouldResendRequest() is true. |
| void ResetConnectionAndRequestForResend(); |
| |
| // Called when we encounter a network error that could be resolved by trying |
| // a new proxy configuration. If there is another proxy configuration to try |
| // then this method sets next_state_ appropriately and returns either OK or |
| // ERR_IO_PENDING depending on whether or not the new proxy configuration is |
| // available synchronously or asynchronously. Otherwise, the given error |
| // code is simply returned. |
| int ReconsiderProxyAfterError(int error); |
| |
| // Decides the policy when the connection is closed before the end of headers |
| // has been read. This only applies to reading responses, and not writing |
| // requests. |
| int HandleConnectionClosedBeforeEndOfHeaders(); |
| |
| // Sets up the state machine to restart the transaction with auth. |
| void PrepareForAuthRestart(HttpAuth::Target target); |
| |
| // Called when we don't need to drain the response body or have drained it. |
| // Resets |connection_| unless |keep_alive| is true, then calls |
| // ResetStateForRestart. Sets |next_state_| appropriately. |
| void DidDrainBodyForAuthRestart(bool keep_alive); |
| |
| // Resets the members of the transaction so it can be restarted. |
| void ResetStateForRestart(); |
| |
| // Returns true if we should try to add a Proxy-Authorization header |
| bool ShouldApplyProxyAuth() const; |
| |
| // Returns true if we should try to add an Authorization header. |
| bool ShouldApplyServerAuth() const; |
| |
| // Builds either the proxy auth header, or the origin server auth header, |
| // as specified by |target|. |
| std::string BuildAuthorizationHeader(HttpAuth::Target target) const; |
| |
| // Returns a log message for all the response headers related to the auth |
| // challenge. |
| std::string AuthChallengeLogMessage() const; |
| |
| // Handles HTTP status code 401 or 407. |
| // HandleAuthChallenge() returns a network error code, or OK on success. |
| // May update |pending_auth_target_| or |response_.auth_challenge|. |
| int HandleAuthChallenge(); |
| |
| // Populates response_.auth_challenge with the challenge information, so that |
| // URLRequestHttpJob can prompt for a username/password. |
| void PopulateAuthChallenge(HttpAuth::Target target, |
| const GURL& auth_origin); |
| |
| // Invalidates any auth cache entries after authentication has failed. |
| // The identity that was rejected is auth_identity_[target]. |
| void InvalidateRejectedAuthFromCache(HttpAuth::Target target, |
| const GURL& auth_origin); |
| |
| // Sets auth_identity_[target] to the next identity that the transaction |
| // should try. It chooses candidates by searching the auth cache |
| // and the URL for a username:password. Returns true if an identity |
| // was found. |
| bool SelectNextAuthIdentityToTry(HttpAuth::Target target, |
| const GURL& auth_origin); |
| |
| // Searches the auth cache for an entry that encompasses the request's path. |
| // If such an entry is found, updates auth_identity_[target] and |
| // auth_handler_[target] with the cache entry's data and returns true. |
| bool SelectPreemptiveAuth(HttpAuth::Target target); |
| |
| bool HaveAuth(HttpAuth::Target target) const { |
| return auth_handler_[target].get() && !auth_identity_[target].invalid; |
| } |
| |
| // Get the {scheme, host, port} for the authentication target |
| GURL AuthOrigin(HttpAuth::Target target) const; |
| |
| // Get the absolute path of the resource needing authentication. |
| // For proxy authentication the path is always empty string. |
| std::string AuthPath(HttpAuth::Target target) const; |
| |
| void MarkBrokenAlternateProtocolAndFallback(); |
| |
| // Returns a string representation of a HttpAuth::Target value that can be |
| // used in log messages. |
| static std::string AuthTargetString(HttpAuth::Target target); |
| |
| static bool g_ignore_certificate_errors; |
| |
| // The following three auth members are arrays of size two -- index 0 is |
| // for the proxy server, and index 1 is for the origin server. |
| // Use the enum HttpAuth::Target to index into them. |
| |
| // auth_handler encapsulates the logic for the particular auth-scheme. |
| // This includes the challenge's parameters. If NULL, then there is no |
| // associated auth handler. |
| scoped_refptr<HttpAuthHandler> auth_handler_[2]; |
| |
| // auth_identity_ holds the (username/password) that should be used by |
| // the auth_handler_ to generate credentials. This identity can come from |
| // a number of places (url, cache, prompt). |
| HttpAuth::Identity auth_identity_[2]; |
| |
| // Whether this transaction is waiting for proxy auth, server auth, or is |
| // not waiting for any auth at all. |pending_auth_target_| is read and |
| // cleared by RestartWithAuth(). |
| HttpAuth::Target pending_auth_target_; |
| |
| CompletionCallbackImpl<HttpNetworkTransaction> io_callback_; |
| CompletionCallback* user_callback_; |
| |
| scoped_refptr<HttpNetworkSession> session_; |
| |
| BoundNetLog net_log_; |
| const HttpRequestInfo* request_; |
| HttpResponseInfo response_; |
| |
| ProxyService::PacRequest* pac_request_; |
| ProxyInfo proxy_info_; |
| |
| scoped_ptr<ClientSocketHandle> connection_; |
| scoped_ptr<HttpStream> http_stream_; |
| scoped_refptr<SpdyStream> spdy_stream_; |
| bool reused_socket_; |
| |
| // True if we've validated the headers that the stream parser has returned. |
| bool headers_valid_; |
| |
| // True if we've logged the time of the first response byte. Used to |
| // prevent logging across authentication activity where we see multiple |
| // responses. |
| bool logged_response_time; |
| |
| bool using_ssl_; // True if handling a HTTPS request |
| ProxyMode proxy_mode_; |
| |
| // True while establishing a tunnel. This allows the HTTP CONNECT |
| // request/response to reuse the STATE_SEND_REQUEST, |
| // STATE_SEND_REQUEST_COMPLETE, STATE_READ_HEADERS, and |
| // STATE_READ_HEADERS_COMPLETE states and allows us to tell them apart from |
| // the real request/response of the transaction. |
| bool establishing_tunnel_; |
| |
| // True if this network transaction is using SPDY instead of HTTP. |
| bool using_spdy_; |
| |
| AlternateProtocolMode alternate_protocol_mode_; |
| |
| // Only valid if |alternate_protocol_mode_| == kUsingAlternateProtocol. |
| HttpAlternateProtocols::Protocol alternate_protocol_; |
| |
| // True if we've used the username/password embedded in the URL. This |
| // makes sure we use the embedded identity only once for the transaction, |
| // preventing an infinite auth restart loop. |
| bool embedded_identity_used_; |
| |
| SSLConfig ssl_config_; |
| |
| std::string request_headers_; |
| |
| // The size in bytes of the buffer we use to drain the response body that |
| // we want to throw away. The response body is typically a small error |
| // page just a few hundred bytes long. |
| enum { kDrainBodyBufferSize = 1024 }; |
| |
| // User buffer and length passed to the Read method. |
| scoped_refptr<IOBuffer> read_buf_; |
| int read_buf_len_; |
| |
| // The time the Start method was called. |
| base::Time start_time_; |
| |
| // The time the DoSSLConnect() method was called (if it got called). |
| base::TimeTicks ssl_connect_start_time_; |
| |
| // The next state in the state machine. |
| State next_state_; |
| }; |
| |
| } // namespace net |
| |
| #endif // NET_HTTP_HTTP_NETWORK_TRANSACTION_H_ |