1 String WwwFormat(Time tm);
2 bool   ScanWwwTime(const char *s, Time& tm);
3 Time   ScanWwwTime(const char *s);
4 
5 String MIMECharsetName(byte charset);
6 
7 String UrlEncode(const char *s, const char *end);
8 String UrlEncode(const char *s, int len);
9 String UrlEncode(const String& s);
10 String UrlDecode(const char *s, const char *end);
11 String UrlDecode(const char *s, int len);
12 String UrlDecode(const String& s);
13 
14 String QPEncode(const char* s);
15 String QPDecode(const char *s, bool undescore_to_space = false);
16 
17 String Base64Encode(const char *s, const char *end);
18 String Base64Encode(const char *s, int len);
19 String Base64Encode(const String& data);
20 String Base64Decode(const char *s, const char *end);
21 String Base64Decode(const char *s, int len);
22 String Base64Decode(const String& data);
23 
24 String DeHtml(const char *s);
25 
26 void   HMAC_SHA1(const byte *text, int text_len, const byte *key, int key_len, byte *digest);
27 String HMAC_SHA1(const String& text, const String& key);
28 String HMAC_SHA1_Hex(const String& text, const String& key);
29 
30 const Index<String>& GetMIMETypes();
31 String FileExtToMIME(const String& ext);
32 String MIMEToFileExt(const String& mime);
33 
34 class IpAddrInfo {
35 	enum { COUNT = 128 };
36 	struct Entry {
37 		const char *host;
38 		const char *port;
39 		int         family;
40 		int         status;
41 		addrinfo   *addr;
42 	};
43 	static Entry     pool[COUNT];
44 
45 	enum {
46 		EMPTY = 0, WORKING, CANCELED, RESOLVED, FAILED
47 	};
48 
49 	String host, port;
50 	int    family;
51 	Entry *entry;
52 	Entry  exe[1];
53 
54 	static void EnterPool();
55 	static void LeavePool();
56 	static auxthread_t auxthread__ Thread(void *ptr);
57 
58 	void Start();
59 
60 	IpAddrInfo(const IpAddrInfo&);
61 
62 public:
63 	enum IpAddrFamily {
64 		FAMILY_ANY = 0, FAMILY_IPV4, FAMILY_IPV6
65 	};
66 	void      Start(const String& host, int port, int family = FAMILY_ANY);
67 	bool      InProgress();
68 	bool      Execute(const String& host, int port, int family = FAMILY_ANY);
69 	addrinfo *GetResult() const;
70 	void      Clear();
71 
72 	IpAddrInfo();
~IpAddrInfo()73 	~IpAddrInfo()           { Clear(); }
74 };
75 
76 struct SSLInfo {
77 	String  cipher;
78 	bool    cert_avail;
79 	bool    cert_verified; // Peer verification not yet working - this is always false
80 	String  cert_subject;
81 	String  cert_issuer;
82 	Date    cert_notbefore;
83 	Date    cert_notafter;
84 	int     cert_version;
85 	String  cert_serial;
86 };
87 
88 enum { WAIT_READ = 1, WAIT_WRITE = 2, WAIT_IS_EXCEPTION = 4 };
89 
90 class TcpSocket : NoCopy {
91 	enum { BUFFERSIZE = 512 };
92 	enum { NONE, CONNECT, ACCEPT, SSL_CONNECTED };
93 	SOCKET                  socket;
94 	int                     mode;
95 	char                    buffer[BUFFERSIZE];
96 	char                   *ptr;
97 	char                   *end;
98 	bool                    is_eof;
99 	bool                    is_error;
100 	bool                    is_timeout;
101 	bool                    is_abort;
102 	bool                    ipv6;
103 
104 	int                     timeout;
105 	int                     waitstep;
106 	int                     done;
107 
108 	int                     global_timeout;
109 	int                     start_time;
110 #if defined(PLATFORM_WIN32) || defined(PLATFORM_BSD)
111 	int                     connection_start;
112 #endif
113 	int                     ssl_start;
114 
115 	int                     errorcode;
116 	String                  errordesc;
117 
118 	struct SSL {
119 		virtual bool  Start() = 0;
120 		virtual bool  Wait(dword flags, int end_time) = 0;
121 		virtual int   Send(const void *buffer, int maxlen) = 0;
122 		virtual int   Recv(void *buffer, int maxlen) = 0;
123 		virtual void  Close() = 0;
124 		virtual dword Handshake() = 0;
125 
~SSLSSL126 		virtual ~SSL() {}
127 	};
128 
129 	One<SSL>                ssl;
130 	One<SSLInfo>            sslinfo;
131 	String                  cert, pkey, sni;
132 	bool                    asn1;
133 
134 	struct SSLImp;
135 	friend struct SSLImp;
136 
137 	static SSL *(*CreateSSL)(TcpSocket& socket);
138 	static SSL *CreateSSLImp(TcpSocket& socket);
139 
140 	friend void  InitCreateSSL();
141 	friend class IpAddrInfo;
142 
143 	int                     GetEndTime() const;
144 	bool                    RawWait(dword flags, int end_time);
145 	bool                    Wait(dword events, int end_time);
146 	SOCKET                  AcceptRaw(dword *ipaddr, int timeout_msec);
147 	bool                    SetupSocket();
148 	bool                    Open(int family, int type, int protocol);
149 	int                     RawRecv(void *buffer, int maxlen);
150 	int                     Recv(void *buffer, int maxlen);
151 	int                     RawSend(const void *buffer, int maxlen);
152 	int                     Send(const void *buffer, int maxlen);
153 	bool                    RawConnect(addrinfo *arp);
154 	void                    RawClose();
155 
156 	void                    ReadBuffer(int end_time);
157 	int                     Get_();
158 	int                     Peek_();
159 	int                     Peek_(int end_time);
Peek(int end_time)160 	int                     Peek(int end_time)          { return ptr < end ? (byte)*ptr : Peek_(end_time); }
161 	bool                    IsGlobalTimeout();
162 
163 	void                    Reset();
164 
165 	void                    SetSockError(const char *context, const char *errdesc);
166 	void                    SetSockError(const char *context);
167 
168 	bool                    WouldBlock();
169 
170 	static int              GetErrorCode();
171 	static void             Init();
172 
173 	TcpSocket(const TcpSocket&);
174 
175 public:
176 	Event<>         WhenWait;
177 
178 	void            SetSockError(const char *context, int code, const char *errdesc);
179 
180 	enum { ERROR_GLOBAL_TIMEOUT = -1000000, ERROR_SSLHANDSHAKE_TIMEOUT, ERROR_LAST };
181 
182 	static String   GetHostName();
183 
GetDone()184 	int             GetDone() const                          { return done; }
185 
IsOpen()186 	bool            IsOpen() const                           { return socket != INVALID_SOCKET; }
187 	bool            IsEof() const;
188 
IsError()189 	bool            IsError() const                          { return is_error; }
ClearError()190 	void            ClearError()                             { is_error = false; errorcode = 0; errordesc.Clear(); }
GetError()191 	int             GetError() const                         { return errorcode; }
GetErrorDesc()192 	String          GetErrorDesc() const                     { return errordesc; }
193 
Abort()194 	void            Abort()                                  { is_abort = true; }
IsAbort()195 	bool            IsAbort() const                          { return is_abort; }
ClearAbort()196 	void            ClearAbort()                             { is_abort = false; }
197 
IsTimeout()198 	bool            IsTimeout() const                        { return is_timeout; }
199 
GetSOCKET()200 	SOCKET          GetSOCKET() const                        { return socket; }
201 	String          GetPeerAddr() const;
202 
203 	void            Attach(SOCKET socket);
204 	bool            Connect(const char *host, int port);
205 	bool            Connect(IpAddrInfo& info);
206 	bool            WaitConnect();
207 	bool            Listen(int port, int listen_count = 5, bool ipv6 = false, bool reuse = true, void* addr = NULL);
208 	bool            Listen(const IpAddrInfo& addr, int port, int listen_count = 5, bool ipv6 = false, bool reuse = true);
209 	bool            Accept(TcpSocket& listen_socket);
210 	void            Close();
211 	void            Shutdown();
212 
213 	void            NoDelay();
214 	void            Linger(int msecs);
NoLinger()215 	void            NoLinger()                               { Linger(Null); }
216 
217 	bool            Wait(dword events);
WaitRead()218 	bool            WaitRead()                               { return Wait(WAIT_READ); }
WaitWrite()219 	bool            WaitWrite()                              { return Wait(WAIT_WRITE); }
220 
Peek()221 	int             Peek()                                   { return ptr < end ? (byte)*ptr : Peek_(); }
Term()222 	int             Term()                                   { return Peek(); }
Get()223 	int             Get()                                    { return ptr < end ? (byte)*ptr++ : Get_(); }
224 	int             Get(void *buffer, int len);
225 	String          Get(int len);
226 
227 	int             Put(const void *s, int len);
Put(const String & s)228 	int             Put(const String& s)                     { return Put(s.Begin(), s.GetLength()); }
229 
230 	bool            GetAll(void *buffer, int len);
231 	String          GetAll(int len);
232 	String          GetLine(int maxlen = 65536);
233 
234 	bool            PutAll(const void *s, int len);
235 	bool            PutAll(const String& s);
236 
237 	bool            StartSSL();
IsSSL()238 	bool            IsSSL() const                            { return ssl; }
239 	dword           SSLHandshake();
240 	void            SSLCertificate(const String& cert, const String& pkey, bool asn1);
241 	void            SSLServerNameIndication(const String& name);
GetSSLInfo()242 	const SSLInfo  *GetSSLInfo() const                       { return ~sslinfo; }
243 
244 	void            Clear();
245 
Timeout(int ms)246 	TcpSocket&      Timeout(int ms)                          { timeout = ms; return *this; }
GetTimeout()247 	int             GetTimeout() const                       { return timeout; }
248 	TcpSocket&      GlobalTimeout(int ms);
NoGlobalTimeout()249 	TcpSocket&      NoGlobalTimeout()                        { return GlobalTimeout(Null); }
Blocking()250 	TcpSocket&      Blocking()                               { return Timeout(Null); }
IsBlocking()251 	bool            IsBlocking()                             { return IsNull(GetTimeout()); }
WaitStep(int ms)252 	TcpSocket&      WaitStep(int ms)                         { waitstep = ms; return *this; }
GetWaitStep()253 	int             GetWaitStep() const                      { return waitstep; }
254 
255 	TcpSocket();
~TcpSocket()256 	~TcpSocket()                                             { Close(); }
257 };
258 
259 class SocketWaitEvent {
260 	Vector<Tuple<int, dword>> socket;
261 	fd_set read[1], write[1], exception[1];
262 	SocketWaitEvent(const SocketWaitEvent &);
263 
264 public:
Clear()265 	void  Clear()                                            { socket.Clear(); }
Add(SOCKET s,dword events)266 	void  Add(SOCKET s, dword events)                        { socket.Add(MakeTuple((int)s, events)); }
Add(TcpSocket & s,dword events)267 	void  Add(TcpSocket& s, dword events)                    { Add(s.GetSOCKET(), events); }
268 	int   Wait(int timeout);
269 	dword Get(int i) const;
270 	dword operator[](int i) const                            { return Get(i); }
271 
272 	SocketWaitEvent();
273 };
274 
275 struct UrlInfo {
276 	String                            url;
277 
278 	String                            scheme;
279 	String                            host;
280 	String                            port;
281 	String                            username;
282 	String                            password;
283 	String                            path;
284 	String                            query;
285 	String                            fragment;
286 
287 	VectorMap<String, String>         parameters;
288 	VectorMap<String, Vector<String>> array_parameters;
289 
ClearUrlInfo290 	void Clear()                      { *this = UrlInfo(); }
291 	void Parse(const String& url);
292 
293 	String operator[](const char *id) const;
294 	const Vector<String>& GetArray(const char *id) const;
295 
UrlInfoUrlInfo296 	UrlInfo() {}
UrlInfoUrlInfo297 	UrlInfo(const String& url)        { Parse(url); }
298 };
299 
300 struct HttpCookie : Moveable<HttpCookie> {
301 	String id;
302 	String value;
303 	String domain;
304 	String path;
305 	String raw;
306 
307 	void Clear();
308 	bool Parse(const String& cookie);
309 };
310 
311 struct HttpHeader {
312 	String                        first_line;
313 	String                        f1, f2, f3;
314 	VectorMap<String, String>     fields;
315 	VectorMap<String, HttpCookie> cookies;
316 	bool                          scgi;
317 
318 	String operator[](const char *id) const                  { return fields.Get(id, Null); }
319 	String GetCookie(const char *id) const;
320 
321 	bool   Response(String& protocol, int& code, String& reason) const;
322 	bool   Request(String& method, String& uri, String& version) const;
323 
GetProtocolHttpHeader324 	String GetProtocol() const                               { return f1; }
325 	int    GetCode() const;
GetReasonHttpHeader326 	String GetReason() const                                 { return f3; }
327 
GetMethodHttpHeader328 	String GetMethod() const                                 { return f1; }
GetURIHttpHeader329 	String GetURI() const                                    { return f2; }
GetVersionHttpHeader330 	String GetVersion() const                                { return f3; }
331 
332 	bool   HasContentLength() const;
333 	int64  GetContentLength() const;
334 
335 	void   Clear();
336 	bool   ParseAdd(const String& hdrs);
337 	bool   Parse(const String& hdrs);
338 	bool   ParseSCGI(const String& scgi_hdr);
339 
340 	bool   Read(TcpSocket& socket);
341 
HttpHeaderHttpHeader342 	HttpHeader()                                             { scgi = false; }
343 
344 private:
345 	void   Add(const String& id, const String& value);
346 	HttpHeader(const HttpHeader&);
347 };
348 
349 class HttpRequest : public TcpSocket {
350 	int          phase;
351 	dword        waitevents;
352 	String       data;
353 	int64        count;
354 
355 	HttpHeader   header;
356 
357 	String       error;
358 	String       body;
359 	int64        content_length;
360 	bool         has_content_length;
361 	bool         chunked_encoding;
362 
363 	enum {
364 		DEFAULT_HTTP_PORT        = 80,
365 		DEFAULT_HTTPS_PORT       = 443
366 	};
367 
368 	int          max_header_size;
369 	int          max_content_size;
370 	int          max_redirects;
371 	int          max_retries;
372 	int          timeout;
373 
374 	String       host;
375 	int          port;
376 	String       proxy_host;
377 	int          proxy_port;
378 	String       proxy_username;
379 	String       proxy_password;
380 	String       ssl_proxy_host;
381 	int          ssl_proxy_port;
382 	String       ssl_proxy_username;
383 	String       ssl_proxy_password;
384 	String       path;
385 	String       phost;
386 	bool         ssl;
387 	bool         ssl_get_proxy;
388 
389 	int          method;
390 	String       custom_method;
391 	String       accept;
392 	String       agent;
393 	bool         force_digest;
394 	bool         is_post;
395 	bool         std_headers;
396 	bool         hasurlvar;
397 	bool		 keep_alive;
398 	bool         all_content;
399 	String       contenttype;
400 	String       username;
401 	String       password;
402 	String       authorization;
403 	String       request_headers;
404 	String       postdata;
405 	String       multipart;
406 	VectorMap<String, HttpCookie> cookies;
407 
408 	String       protocol;
409 	int          status_code;
410 	String       reason_phrase;
411 
412 	int          start_time;
413 	int          retry_count;
414 	int          redirect_count;
415 
416 	int          chunk;
417 
418 	IpAddrInfo   addrinfo;
419 	bool         gzip;
420 	Zlib         z;
421 
422 	Stream      *poststream;
423 	int64        postlen;
424 
425 	String       chunk_crlf;
426 
427 	void         Init();
428 
429 	void         StartPhase(int s);
430 	void         Start();
431 	void         Dns();
432 	void         StartConnect();
433 	void         ProcessSSLProxyResponse();
434 	void         AfterConnect();
435 	void         StartRequest();
436 	bool         SendingData(bool request = false);
437 
438 	bool         ReadingHeader();
439 	bool         ReadingTrailer();
440 	void         StartBody();
441 	bool         ReadingBody();
442 	void         ReadingChunkHeader();
443 	void         Finish();
444 	bool         IsRequestTimeout();
445 	void         CopyCookies();
446 
447 	void         HttpError(const char *s);
448 	void         Out(const void *ptr, int size);
449 
450 	String       CalculateDigest(const String& authenticate) const;
451 
452 public:
453 	enum {
454 		METHOD_GET     = 0,
455 		METHOD_POST    = 1,
456 		METHOD_HEAD    = 2,
457 		METHOD_PUT     = 3,
458 		METHOD_DELETE  = 4,
459 		METHOD_TRACE   = 5,
460 		METHOD_OPTIONS = 6,
461 		METHOD_CONNECT = 7,
462 		METHOD_PATCH   = 8,
463 	};
464 
465 	Event<const void *, int>  WhenContent;
466 	Event<>                   WhenStart;
467 	Event<>                   WhenDo;
468 	Gate<>                    WhenAuthenticate;
469 
MaxHeaderSize(int m)470 	HttpRequest&  MaxHeaderSize(int m)                   { max_header_size = m; return *this; }
MaxContentSize(int m)471 	HttpRequest&  MaxContentSize(int m)                  { max_content_size = m; return *this; }
MaxRedirect(int n)472 	HttpRequest&  MaxRedirect(int n)                     { max_redirects = n; return *this; }
MaxRetries(int n)473 	HttpRequest&  MaxRetries(int n)                      { max_retries = n; return *this; }
RequestTimeout(int ms)474 	HttpRequest&  RequestTimeout(int ms)                 { timeout = ms; return *this; }
ChunkSize(int n)475 	HttpRequest&  ChunkSize(int n)                       { chunk = n; return *this; }
476 	HttpRequest&  AllContent(bool b = true)              { all_content = b; return *this; }
477 
478 	HttpRequest&  Method(int m, const char *custom_name = NULL);
GET()479 	HttpRequest&  GET()                                  { return Method(METHOD_GET); }
POST()480 	HttpRequest&  POST()                                 { return Method(METHOD_POST); }
HEAD()481 	HttpRequest&  HEAD()                                 { return Method(METHOD_HEAD); }
PUT()482 	HttpRequest&  PUT()                                  { return Method(METHOD_PUT); }
DEL()483 	HttpRequest&  DEL()                                  { return Method(METHOD_DELETE); }
TRACE()484 	HttpRequest&  TRACE()                                { return Method(METHOD_TRACE); }
OPTIONS()485 	HttpRequest&  OPTIONS()                              { return Method(METHOD_OPTIONS); }
CONNECT()486 	HttpRequest&  CONNECT()                              { return Method(METHOD_CONNECT); }
PATCH()487 	HttpRequest&  PATCH()                                { return Method(METHOD_PATCH); }
488 
Host(const String & h)489 	HttpRequest&  Host(const String& h)                  { host = h; return *this; }
Port(int p)490 	HttpRequest&  Port(int p)                            { port = p; return *this; }
491 	HttpRequest&  SSL(bool b = true)                     { ssl = b; return *this; }
Path(const String & p)492 	HttpRequest&  Path(const String& p)                  { path = p; return *this; }
Authorization(const String & h)493 	HttpRequest&  Authorization(const String& h)         { authorization = h; return *this; }
User(const String & u,const String & p)494 	HttpRequest&  User(const String& u, const String& p) { username = u; password = p; return *this; }
Digest()495 	HttpRequest&  Digest()                               { force_digest = true; return *this; }
Digest(const String & u,const String & p)496 	HttpRequest&  Digest(const String& u, const String& p) { User(u, p); return Digest(); }
SetDigest(const String & d)497 	HttpRequest&  SetDigest(const String& d)             { return Authorization("Digest " + d); }
498 	HttpRequest&  Url(const char *url);
499 	HttpRequest&  UrlVar(const char *id, const String& data);
operator()500 	HttpRequest&  operator()(const char *id, const String& data) { return UrlVar(id, data); }
PostData(const String & pd)501 	HttpRequest&  PostData(const String& pd)              { postdata = pd; poststream = NULL; return *this; }
502 	HttpRequest&  PostStream(Stream& s, int64 len = Null);
503 
504 	bool          ResolveDigestAuthentication();
505 
PostUData(const String & pd)506 	HttpRequest&  PostUData(const String& pd)             { return PostData(UrlEncode(pd)); }
Post(const String & data)507 	HttpRequest&  Post(const String& data)                { POST(); return PostData(data); }
508 	HttpRequest&  Post(const char *id, const String& data);
509 	HttpRequest&  Part(const char *id, const String& data,
510 	                   const char *content_type = NULL, const char *filename = NULL);
511 
ClearPost()512 	HttpRequest&  ClearPost()                             { PostData(Null); poststream = NULL; ; multipart.Clear(); GET(); return *this; }
513 
Headers(const String & h)514 	HttpRequest&  Headers(const String& h)                { request_headers = h; return *this; }
ClearHeaders()515 	HttpRequest&  ClearHeaders()                          { return Headers(Null); }
AddHeaders(const String & h)516 	HttpRequest&  AddHeaders(const String& h)             { request_headers.Cat(h); return *this; }
517 	HttpRequest&  Header(const char *id, const String& data);
518 
519 	HttpRequest&  Cookie(const HttpCookie& c);
520 	HttpRequest&  Cookie(const String& id, const String& value,
521 	                     const String& domain = Null, const String& path = Null);
522 	HttpRequest&  CopyCookies(const HttpRequest& r);
ClearCookies()523 	HttpRequest&  ClearCookies()                          { cookies.Clear(); return *this; }
524 
StdHeaders(bool sh)525 	HttpRequest&  StdHeaders(bool sh)                     { std_headers = sh; return *this; }
NoStdHeaders()526 	HttpRequest&  NoStdHeaders()                          { return StdHeaders(false); }
Accept(const String & a)527 	HttpRequest&  Accept(const String& a)                 { accept = a; return *this; }
UserAgent(const String & a)528 	HttpRequest&  UserAgent(const String& a)              { agent = a; return *this; }
ContentType(const String & a)529 	HttpRequest&  ContentType(const String& a)            { contenttype = a; return *this; }
530 	HttpRequest&  KeepAlive(bool ka = true)               { keep_alive = ka; return *this;}
531 
Proxy(const String & host,int port)532 	HttpRequest&  Proxy(const String& host, int port)            { proxy_host = host; proxy_port = port; return *this; }
533 	HttpRequest&  Proxy(const char *p);
ProxyAuth(const String & u,const String & p)534 	HttpRequest&  ProxyAuth(const String& u, const String& p)    { proxy_username = u; proxy_password = p; return *this; }
535 
SSLProxy(const String & host,int port)536 	HttpRequest&  SSLProxy(const String& host, int port)         { ssl_proxy_host = host; ssl_proxy_port = port; return *this; }
537 	HttpRequest&  SSLProxy(const char *p);
SSLProxyAuth(const String & u,const String & p)538 	HttpRequest&  SSLProxyAuth(const String& u, const String& p) {  ssl_proxy_username = u; ssl_proxy_password = p; return *this; }
539 	HttpRequest&  SSLProxyGET(bool b = true)                     { ssl_get_proxy = b; return *this; }
540 
CommonProxy(const String & host,int port)541 	HttpRequest&  CommonProxy(const String& host, int port)         { Proxy(host, port); return SSLProxy(host, port); }
CommonProxy(const char * p)542 	HttpRequest&  CommonProxy(const char *p)                        { Proxy(p); return SSLProxy(p); }
CommonProxyAuth(const String & u,const String & p)543 	HttpRequest&  CommonProxyAuth(const String& u, const String& p) { ProxyAuth(u, p); return SSLProxyAuth(u, p); }
544 
IsSocketError()545 	bool         IsSocketError() const                    { return TcpSocket::IsError(); }
IsHttpError()546 	bool         IsHttpError() const                      { return !IsNull(error) ; }
IsError()547 	bool         IsError() const                          { return IsSocketError() || IsHttpError(); }
GetErrorDesc()548 	String       GetErrorDesc() const                     { return IsSocketError() ? TcpSocket::GetErrorDesc() : error; }
ClearError()549 	void         ClearError()                             { TcpSocket::ClearError(); error.Clear(); }
550 
GetHeader(const char * id)551 	String       GetHeader(const char *id)                { return header[id]; }
552 	String       operator[](const char *id)               { return GetHeader(id); }
553 	String       GetRedirectUrl();
554 	bool         HasContentLength();
555 	int64        GetContentLength();
GetStatusCode()556 	int          GetStatusCode() const                    { return status_code; }
GetReasonPhrase()557 	String       GetReasonPhrase() const                  { return reason_phrase; }
558 
GetHttpHeader()559 	const HttpHeader& GetHttpHeader() const               { return header; }
GetCookie(const char * id)560 	String       GetCookie(const char *id)                { return header.GetCookie(id); }
561 
GetContent()562 	String       GetContent() const                       { return body; }
563 	String       operator~() const                        { return GetContent(); }
String()564 	operator     String() const                           { return GetContent(); }
ClearContent()565 	void         ClearContent()                           { body.Clear(); }
566 
567 	enum Phase {
568 		BEGIN, START, DNS,
569 		SSLPROXYREQUEST, SSLPROXYRESPONSE, SSLHANDSHAKE,
570 		REQUEST, HEADER, BODY,
571 		CHUNK_HEADER, CHUNK_BODY, CHUNK_CRLF, TRAILER,
572 		FINISHED, FAILED,
573 	};
574 
575 	bool    Do();
GetWaitEvents()576 	dword   GetWaitEvents()                       { return waitevents; }
GetPhase()577 	int     GetPhase() const                      { return phase; }
578 	String  GetPhaseName() const;
InProgress()579 	bool    InProgress() const                    { return phase != FAILED && phase != FINISHED; }
IsFailure()580 	bool    IsFailure() const                     { return phase == FAILED; }
IsSuccess()581 	bool    IsSuccess() const                     { return phase == FINISHED && status_code >= 200 && status_code < 300; }
582 
583 	String  Execute();
584 
585 	void    New();
586 	void    NewRequest();
587 	void    Clear();
588 
589 	HttpRequest();
590 	HttpRequest(const char *url);
591 
592 	static void  Trace(bool b = true);
593 	static void  TraceHeader(bool b = true);
594 	static void  TraceBody(bool b = true);
595 	static void  TraceShort(bool b = true);
596 };
597 
598 bool HttpResponse(TcpSocket& socket, bool scgi, int code, const char *phrase,
599                   const char *content_type = NULL, const String& data = Null,
600                   const char *server = NULL, bool gzip = false);
601 
602 #include <Core/Core.h>
603 
604 class WebSocket {
605 	String     error;
606 
607 	TcpSocket  std_socket;
608 	TcpSocket *socket;
609 
610 	String     uri;
611 	String     host;
612 	IpAddrInfo addrinfo;
613 	bool       ssl;
614 	String     request_headers;
615 
616 	String     data;
617 	int        data_pos;
618 
619 	int        opcode;
620 	int64      length;
621 	bool       mask;
622 	int        key[4];
623 
624 	struct Input : Moveable<Input> {
625 		dword  opcode;
626 		String data;
627 	};
628 
629 	BiVector<Input>  in_queue;
630 
631 	BiVector<String> out_queue;
632 	int              out_at;
633 
634 	bool             close_sent;
635 	bool             close_received;
636 
637 	dword            current_opcode;
638 
639 	bool             client;
640 
641 	enum {
642 		HTTP_REQUEST_HEADER = -100,
643 		HTTP_RESPONSE_HEADER = -101,
644 		READING_FRAME_HEADER = -102,
645 		DNS = -103,
646 		SSL_HANDSHAKE = -104,
647 
648 		FIN = 0x80,
649 		TEXT = 0x1,
650 		BINARY = 0x2,
651 		CLOSE = 0x8,
652 		PING = 0x9,
653 		PONG = 0xa,
654 
655 		MASK = 0x80,
656 	};
657 
658 	void Clear();
659 	void Error(const String& error);
660 
661 	void Out(const String& s);
662 
663 	void Output();
664 
665 	void StartConnect();
666 	void Dns();
667 	void SSLHandshake();
668 	void SendRequest();
669 	bool ReadHttpHeader();
670 	void ResponseHeader();
671 	void RequestHeader();
672 	void FrameHeader();
673 	void FrameData();
674 
675 	int GetFinIndex() const;
676 
677 	void   SendRaw(int hdr, const String& data, dword mask = 0);
678 	void   Do0();
679 
680 	static String FormatBlock(const String& s);
681 
682 public:
683 	WebSocket& NonBlocking(bool b = true)               { socket->Timeout(b ? 0 : Null); return *this; }
684 
Headers(const String & h)685 	WebSocket&  Headers(const String& h)                { request_headers = h; return *this; }
ClearHeaders()686 	WebSocket&  ClearHeaders()                          { return Headers(Null); }
AddHeaders(const String & h)687 	WebSocket&  AddHeaders(const String& h)             { request_headers.Cat(h); return *this; }
688 	WebSocket&  Header(const char *id, const String& data);
689 
GetHeaders()690 	String      GetHeaders()                            { return request_headers; }
691 
IsBlocking()692 	bool   IsBlocking() const                           { return IsNull(socket->GetTimeout()); }
693 
IsError()694 	bool   IsError() const                              { return socket->IsError() || error.GetCount(); }
GetError()695 	String GetError() const                             { return Nvl(socket->GetErrorDesc(), error); }
696 
697 	bool   Accept(TcpSocket& listener_socket);
698 	bool   Connect(const String& uri, const String& host, bool ssl, int port);
Connect(const String & uri,const String & host,bool ssl)699 	bool   Connect(const String& uri, const String& host, bool ssl) { return Connect(uri, host, ssl, ssl ? 440 : 80); }
700 	bool   Connect(const String& url);
701 
702 	void   Do();
703 
704 	String Receive();
IsFin()705 	bool   IsFin() const                                { return current_opcode & FIN; }
IsText()706 	bool   IsText() const                               { return current_opcode & TEXT; }
IsBinary()707 	bool   IsBinary() const                             { return current_opcode & BINARY; }
708 
SendText(const String & data)709 	void   SendText(const String& data)                 { SendRaw(FIN|TEXT, data); }
SendTextMasked(const String & data)710 	void   SendTextMasked(const String& data)           { SendRaw(FIN|TEXT, data, MASK); }
SendBinary(const String & data)711 	void   SendBinary(const String& data)               { SendRaw(FIN|BINARY, data); }
Ping(const String & data)712 	void   Ping(const String& data)                     { SendRaw(FIN|PING, data); }
713 
BeginText(const String & data)714 	void   BeginText(const String& data)                { SendRaw(TEXT, data); }
BeginBinary(const String & data)715 	void   BeginBinary(const String& data)              { SendRaw(BINARY, data); }
Continue(const String & data)716 	void   Continue(const String& data)                 { SendRaw(0, data); }
Fin(const String & data)717 	void   Fin(const String& data)                      { SendRaw(FIN, data); }
718 
719 	void   Close(const String& msg = Null, bool wait_reply = false);
IsOpen()720 	bool   IsOpen() const                               { return socket->IsOpen(); }
IsClosed()721 	bool   IsClosed() const                             { return !IsOpen(); }
722 
GetWaitEvents()723 	dword  GetWaitEvents() const                        { return WAIT_READ|(!!out_queue.GetCount() * WAIT_WRITE); }
GetSOCKET()724 	SOCKET GetSOCKET() const                            { return socket ? socket->GetSOCKET() : INVALID_SOCKET; }
GetPeerAddr()725 	String GetPeerAddr() const                          { return socket ? socket->GetPeerAddr() : ""; }
AddTo(SocketWaitEvent & e)726 	void   AddTo(SocketWaitEvent& e)                    { e.Add(*socket, GetWaitEvents()); }
727 
728 	static void Trace(bool b = true);
729 
730 	WebSocket();
731 
732 // backward compatibility:
733 	bool   WebAccept(TcpSocket& socket, HttpHeader& hdr);
734 	bool   WebAccept(TcpSocket& socket);
735 
GetOpCode()736 	int    GetOpCode() const { return current_opcode & 15; }
737 
SendText(const String & data,bool fin)738 	bool   SendText(const String& data, bool fin)                   { SendRaw((fin ? 0x80 : 0)|TEXT, data); return !IsError(); }
739 	bool   SendText(const void *data, int len, bool fin = true)     { return SendText(String((char *)data, len), fin); }
740 
SendBinary(const String & data,bool fin)741 	bool   SendBinary(const String& data, bool fin)                 { SendRaw((fin ? 0x80 : 0)|BINARY, data); return !IsError(); }
742 	bool   SendBinary(const void *data, int len, bool fin = true)   { return SendText(String((char *)data, len), fin); }
743 
GetErrorDesc()744 	String GetErrorDesc() const                                     { return GetError(); }
745 
746 // keep mispeled method names
Recieve()747 	String Recieve()    { return Receive(); }
748 };
749 
750 void ParseProxyUrl(const char *p, String& proxy_host, int& proxy_port);
751