1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_HttpServer_h 8 #define mozilla_dom_HttpServer_h 9 10 #include "nsISupportsImpl.h" 11 #include "mozilla/DOMEventTargetHelper.h" 12 #include "nsITLSServerSocket.h" 13 #include "nsIAsyncInputStream.h" 14 #include "nsIAsyncOutputStream.h" 15 #include "mozilla/Variant.h" 16 #include "nsIRequestObserver.h" 17 #include "mozilla/MozPromise.h" 18 #include "nsITransportProvider.h" 19 #include "nsILocalCertService.h" 20 21 class nsIX509Cert; 22 23 namespace mozilla { 24 namespace dom { 25 26 extern bool 27 ContainsToken(const nsCString& aList, const nsCString& aToken); 28 29 class InternalRequest; 30 class InternalResponse; 31 32 class HttpServerListener 33 { 34 public: 35 // switch to NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING when that lands 36 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; 37 NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; 38 39 virtual void OnServerStarted(nsresult aStatus) = 0; 40 virtual void OnRequest(InternalRequest* aRequest) = 0; 41 virtual void OnWebSocket(InternalRequest* aConnectRequest) = 0; 42 virtual void OnServerClose() = 0; 43 }; 44 45 class HttpServer final : public nsIServerSocketListener, 46 public nsILocalCertGetCallback 47 { 48 public: 49 HttpServer(); 50 51 NS_DECL_ISUPPORTS 52 NS_DECL_NSISERVERSOCKETLISTENER 53 NS_DECL_NSILOCALCERTGETCALLBACK 54 55 void Init(int32_t aPort, bool aHttps, HttpServerListener* aListener); 56 57 void SendResponse(InternalRequest* aRequest, InternalResponse* aResponse); 58 already_AddRefed<nsITransportProvider> 59 AcceptWebSocket(InternalRequest* aConnectRequest, 60 const Optional<nsAString>& aProtocol, 61 ErrorResult& aRv); 62 void SendWebSocketResponse(InternalRequest* aConnectRequest, 63 InternalResponse* aResponse); 64 65 void Close(); 66 67 void GetCertKey(nsACString& aKey); 68 GetPort()69 int32_t GetPort() 70 { 71 return mPort; 72 } 73 74 private: 75 ~HttpServer(); 76 77 nsresult StartServerSocket(nsIX509Cert* aCert); 78 void NotifyStarted(nsresult aStatus); 79 80 class TransportProvider final : public nsITransportProvider 81 { 82 public: 83 NS_DECL_ISUPPORTS 84 NS_DECL_NSITRANSPORTPROVIDER 85 86 void SetTransport(nsISocketTransport* aTransport, 87 nsIAsyncInputStream* aInput, 88 nsIAsyncOutputStream* aOutput); 89 90 private: 91 virtual ~TransportProvider(); 92 void MaybeNotify(); 93 94 nsCOMPtr<nsIHttpUpgradeListener> mListener; 95 nsCOMPtr<nsISocketTransport> mTransport; 96 nsCOMPtr<nsIAsyncInputStream> mInput; 97 nsCOMPtr<nsIAsyncOutputStream> mOutput; 98 }; 99 100 class Connection final : public nsIInputStreamCallback 101 , public nsIOutputStreamCallback 102 , public nsITLSServerSecurityObserver 103 { 104 public: 105 Connection(nsISocketTransport* aTransport, 106 HttpServer* aServer, 107 nsresult& rv); 108 109 NS_DECL_ISUPPORTS 110 NS_DECL_NSIINPUTSTREAMCALLBACK 111 NS_DECL_NSIOUTPUTSTREAMCALLBACK 112 NS_DECL_NSITLSSERVERSECURITYOBSERVER 113 114 bool TryHandleResponse(InternalRequest* aRequest, 115 InternalResponse* aResponse); 116 already_AddRefed<nsITransportProvider> 117 HandleAcceptWebSocket(const Optional<nsAString>& aProtocol, 118 ErrorResult& aRv); 119 void HandleWebSocketResponse(InternalResponse* aResponse); HasPendingWebSocketRequest(InternalRequest * aRequest)120 bool HasPendingWebSocketRequest(InternalRequest* aRequest) 121 { 122 return aRequest == mPendingWebSocketRequest; 123 } 124 125 void Close(); 126 127 private: 128 ~Connection(); 129 130 void SetSecurityObserver(bool aListen); 131 132 static nsresult ReadSegmentsFunc(nsIInputStream* aIn, 133 void* aClosure, 134 const char* aBuffer, 135 uint32_t aToOffset, 136 uint32_t aCount, 137 uint32_t* aWriteCount); 138 nsresult ConsumeInput(const char*& aBuffer, 139 const char* aEnd); 140 nsresult ConsumeLine(const char* aBuffer, 141 size_t aLength); 142 void MaybeAddPendingHeader(); 143 144 void QueueResponse(InternalResponse* aResponse); 145 146 RefPtr<HttpServer> mServer; 147 nsCOMPtr<nsISocketTransport> mTransport; 148 nsCOMPtr<nsIAsyncInputStream> mInput; 149 nsCOMPtr<nsIAsyncOutputStream> mOutput; 150 151 enum { eRequestLine, eHeaders, eBody, ePause } mState; 152 RefPtr<InternalRequest> mPendingReq; 153 uint32_t mPendingReqVersion; 154 nsCString mInputBuffer; 155 nsCString mPendingHeaderName; 156 nsCString mPendingHeaderValue; 157 uint32_t mRemainingBodySize; 158 nsCOMPtr<nsIAsyncOutputStream> mCurrentRequestBody; 159 bool mCloseAfterRequest; 160 161 typedef Pair<RefPtr<InternalRequest>, 162 RefPtr<InternalResponse>> PendingRequest; 163 nsTArray<PendingRequest> mPendingRequests; 164 RefPtr<MozPromise<nsresult, bool, false>> mOutputCopy; 165 166 RefPtr<InternalRequest> mPendingWebSocketRequest; 167 RefPtr<TransportProvider> mWebSocketTransportProvider; 168 169 struct OutputBuffer { 170 nsCString mString; 171 nsCOMPtr<nsIInputStream> mStream; 172 bool mChunked; 173 }; 174 175 nsTArray<OutputBuffer> mOutputBuffers; 176 }; 177 178 friend class Connection; 179 180 RefPtr<HttpServerListener> mListener; 181 nsCOMPtr<nsIServerSocket> mServerSocket; 182 nsCOMPtr<nsIX509Cert> mCert; 183 184 nsTArray<RefPtr<Connection>> mConnections; 185 186 int32_t mPort; 187 bool mHttps; 188 }; 189 190 } // namespace dom 191 } // namespace mozilla 192 193 #endif // mozilla_dom_HttpServer_h 194