Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include "../auto-ptr.h"
- #include "../byte-array.h"
- #include "../object.h"
- #include "../promise.h"
- #include "common-http.h"
- #include "message.h"
- namespace fn {
- namespace crypto {
- class TLSStream;
- }
- } // namespace fn
- namespace fn {
- FN_UNINDENT
- namespace http {
- class ProxyStateFactory;
- class FN_EXPORT ClientSession : public RefCountedObject
- {
- public:
- using AuthorizationCallback =
- Function<Optional<Promise<http::Request>>(const http::Request & request, const http::Response &)>;
- using RedirectCallback = Function<bool(http::Request & newRequest, int count)>;
- class Request : public RefCountedObject
- {
- public:
- // can be modified until sent(), after that modifications will be ignored
- virtual http::Request & request() = 0;
- virtual const http::Request & request() const = 0;
- // available after onResponseReceived callback is invoked
- virtual const Optional<http::Response> & response() const = 0;
- // Must be set before send()
- virtual void setChunked(bool chunked) = 0;
- // Must be set before send()
- virtual void setBody(ByteArray body) = 0;
- // Returns true if the underlying stream is in encrypted state
- virtual bool secure() const = 0;
- // May be called after promise returned from send() is fulfilled
- //
- // With chunked transfer every call will result in one chunk being sent; Send
- // empty buffer to finish request (last chunk).
- //
- virtual Promise<void> appendBody(const UInt8 * data, SizeType size) = 0;
- virtual Promise<void> appendBody(ByteArray buffer) = 0;
- // Allows postprocessing / intercepting redirect; You can inspect or modify
- // new request from the callback. Request will contain new (redirect) URL
- // Returning false from callback will abort the redirect and process the
- // response regularly
- virtual void onRedirect(RedirectCallback cb) = 0;
- // Called during authorization request; Callback can return Promise for new
- // authenticated request or NullOptional to finish current response
- virtual void onAuthorizationRequired(AuthorizationCallback cb) = 0;
- // If upgrade callback is set, it will be invoked during upgrade response; In
- // this case, none of the onResponseReceived, onResponseData and
- // onResponseDone callbacks will be called. Callback must take ownership of
- // the stream and can use it for new protocol. The stream will have reading
- // stopped just after the headers
- // As special case, onUpgrade is also called during CONNECT requests when
- // response is 200 (OK)
- virtual void onUpgrade(Function<void(ap_<uv::Stream>)> cb) = 0;
- // Received when response headers are received, before data
- virtual void onResponseReceived(Function<void()> cb) = 0;
- // Called possibly repeatedly for response data
- virtual void onResponseData(Function<void(const UInt8 *, SizeType)> cb) = 0;
- // Called when response is finished;
- virtual void onResponseDone(Function<void()> cb) = 0;
- // Called on connection error; This means system error, not HTTP error status
- virtual void onConnectionError(Function<void(std::exception_ptr e)> cb) = 0;
- // Sends the request; Any modifications to request past this point may be
- // ignored
- virtual Promise<void> send() = 0;
- // Convenience method that sends the request and gathers entire response
- virtual Promise<ByteArray> sendAndReceive() = 0;
- // Cancels the request. Connection will be closed, callbacks will be removed.
- virtual void cancel() = 0;
- };
- //
- //
- //
- // Creates new ClientSession instance using system proxy factory
- static ap<ClientSession> create(ap_<crypto::TLSContext> TLSContext);
- static ap<ClientSession> create(ap_<ProxyStateFactory> factory);
- //
- //
- //
- // Creates HTTP Request instance
- virtual ap<Request> createRequest(const String & method,
- const URL & url) = 0; // must be absolute
- // request URL must be absolute
- virtual ap<Request> createRequest(const http::Request & request) = 0;
- //
- // Settings, changing these will not affect existing or pooled connections
- //
- // If connection can not be established within the timeout request will fail with
- // TimedOutException
- void setConnectionTimeout(const Duration & timeout) { _connectionTimeout = timeout; }
- const Duration & connectionTimeout() const { return _connectionTimeout; }
- // TCP options
- void setNoDelay(bool noDelay) { _noDelay = noDelay; }
- bool noDelay() const { return _noDelay; }
- void setTCPKeepAlive(bool keepAlive) { _keepAlive = keepAlive; }
- bool tcpKeepAlive() const { return _keepAlive; }
- void setTCPKeepAliveTimeout(const Duration & timeout) { _tcpKeepAliveTimeout = timeout; }
- const Duration & tcpKeepAliveTimeout() const { return _tcpKeepAliveTimeout; }
- // HTTP options
- void setHTTPKeepAliveTimeout(const Duration & timeout) { _httpKeepAliveTimeout = timeout; }
- const Duration & httpKeepAliveTimeout() const { return _httpKeepAliveTimeout; }
- // Per session authorization callback; Can be overriden on individual requests
- void onAuthorizationRequired(AuthorizationCallback cb) { _onAuthorizationRequired = FN_MOVE(cb); }
- // Per session redirect callback; Can be overriden on individual requests
- void onRedirect(RedirectCallback cb) { _onRedirect = FN_MOVE(cb); }
- private:
- Duration _connectionTimeout = Duration::withSeconds(30);
- bool _noDelay = true;
- bool _keepAlive = true;
- Duration _tcpKeepAliveTimeout = Duration::withSeconds(60);
- Duration _httpKeepAliveTimeout = Duration::withSeconds(60);
- protected:
- AuthorizationCallback _onAuthorizationRequired;
- RedirectCallback _onRedirect;
- };
- //
- // Represents proxy state for individual connection; Responsible for
- // creating TLS stream and processing individual requests
- //
- class FN_EXPORT ProxyState : public RefCountedObject
- {
- public:
- virtual Promise<ap<crypto::TLSStream>> createStream(const http::Request & request) = 0;
- virtual void processRequest(http::Request & request) = 0;
- };
- //
- // Creates proxy state for individual requests
- //
- class FN_EXPORT ProxyStateFactory : public RefCountedObject
- {
- public:
- virtual Promise<ap<ProxyState>> createProxyState(const http::Request & request) = 0;
- };
- //
- // Proxy state that creates direct connection (not proxied)
- //
- class FN_EXPORT PassthroughProxyState : public ProxyState
- {
- public:
- PassthroughProxyState(ap_<crypto::TLSContext> context);
- ~PassthroughProxyState() override;
- Promise<ap<crypto::TLSStream>> createStream(const http::Request & request) override;
- void processRequest(http::Request & request) override;
- private:
- ap<crypto::TLSContext> _context;
- };
- //
- // For every request creates PassthroughProxyState
- //
- class FN_EXPORT PassthroughProxyStateFactory : public ProxyStateFactory
- {
- public:
- PassthroughProxyStateFactory(ap_<crypto::TLSContext> context);
- Promise<ap<ProxyState>> createProxyState(const http::Request & request) override;
- protected:
- ~PassthroughProxyStateFactory() override;
- private:
- ap<crypto::TLSContext> _context;
- };
- // Lowlevel API for single HTTP stream
- class FN_EXPORT SimpleClientSession : public RefCountedObject, private ResponseParserDelegate
- {
- public:
- class Delegate
- {
- public:
- enum class ResponseResult // must match values from parser
- {
- CONTINUE = 0,
- FORCE_NO_BODY = 1,
- FORCE_UPGRADE = 2
- };
- // Invoked when server can accept client body; it is possible for this
- // callback to be invoked from within sendRequest()
- virtual void onCanSendBody() = 0;
- // Invoked when response headers are available
- virtual ResponseResult onResponseHeaders(Response && response, bool keepAlive, bool upgrade) = 0;
- // Periodically invoked on response data
- virtual void onResponseData(const UInt8 * data, SizeType size) = 0;
- // Possibly invoked on additional final headers after chunked response
- virtual void onAdditionalResponseHeader(const String & name, const String & value) = 0;
- // Invoked when respone is finished
- virtual void onResponseDone() = 0;
- // Invoked on parsing / connection errro (not on HTTP error code);
- // After this the connection and client session should be discarded
- virtual void onError(std::exception_ptr error) = 0;
- virtual ~Delegate() = default;
- };
- // Sends the request
- // It is not permitted to call this while another request is in progress, or the
- // request has been cancelled, or after error
- void sendRequest(const Request & request);
- // Can only be called after onCanSendBody callback; Callback will be invoked after
- // successful write; Callback will not be invoked after request was cancelled or
- // after error
- void appendRequestBody(const UInt8 * data, SizeType size, Function<void()> done = nullptr);
- // Can only be called after onCanSendBody callback; Callback will be invoked after
- // successful write; Callback will not be invoked after request was cancelled or
- // after error
- void appendRequestBody(ByteArray buffer, Function<void()> done = nullptr);
- // reading will be stopped and no callbacks will be invoked; It is not possible to
- // reuse cancelled client session
- void cancel();
- // constructor
- SimpleClientSession(ap_<uv::Stream> stream, Delegate & delegate);
- //
- ~SimpleClientSession() override;
- private:
- OnMessageResult onMessageHeader(Response && message, bool keepAlive, bool upgrade) override;
- void onMessageData(const UInt8 * data, SizeType size) override;
- void onMessageAdditionalHeader(const String & name, const String & value) override;
- void onMessageDone(bool & stopParsing) override;
- void onError(std::exception_ptr error) override;
- void write(const UInt8 * data, SizeType size, Function<void()> done = nullptr);
- void write(ByteArray, Function<void()> done = nullptr);
- void handleError(std::exception_ptr error);
- ap<uv::Stream> _stream;
- Delegate * _delegate;
- bool _inProgress = false;
- bool _hadError = false;
- bool _cancelled = false;
- bool _canAppendBody = false;
- bool _receivedAnything = false;
- bool _requestConnectionClose = false;
- bool _stopReading = false;
- int _lastStatusCode = 0;
- UniquePtr<ResponseParser> _parser;
- ap<SimpleClientSession> _instance;
- };
- } // namespace http
- } // namespace fn
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement