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