ws.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "curl_setup.h"
  25. #include <curl/curl.h>
  26. #ifdef USE_WEBSOCKETS
  27. #include "urldata.h"
  28. #include "dynbuf.h"
  29. #include "rand.h"
  30. #include "curl_base64.h"
  31. #include "sendf.h"
  32. #include "multiif.h"
  33. #include "ws.h"
  34. #include "easyif.h"
  35. #include "transfer.h"
  36. #include "nonblock.h"
  37. /* The last 3 #include files should be in this order */
  38. #include "curl_printf.h"
  39. #include "curl_memory.h"
  40. #include "memdebug.h"
  41. struct wsfield {
  42. const char *name;
  43. const char *val;
  44. };
  45. CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req)
  46. {
  47. unsigned int i;
  48. CURLcode result = CURLE_OK;
  49. unsigned char rand[16];
  50. char *randstr;
  51. size_t randlen;
  52. char keyval[40];
  53. struct SingleRequest *k = &data->req;
  54. struct wsfield heads[]= {
  55. {
  56. /* The request MUST contain an |Upgrade| header field whose value
  57. MUST include the "websocket" keyword. */
  58. "Upgrade:", "websocket"
  59. },
  60. {
  61. /* The request MUST contain a |Connection| header field whose value
  62. MUST include the "Upgrade" token. */
  63. "Connection:", "Upgrade",
  64. },
  65. {
  66. /* The request MUST include a header field with the name
  67. |Sec-WebSocket-Version|. The value of this header field MUST be
  68. 13. */
  69. "Sec-WebSocket-Version:", "13",
  70. },
  71. {
  72. /* The request MUST include a header field with the name
  73. |Sec-WebSocket-Key|. The value of this header field MUST be a nonce
  74. consisting of a randomly selected 16-byte value that has been
  75. base64-encoded (see Section 4 of [RFC4648]). The nonce MUST be
  76. selected randomly for each connection. */
  77. "Sec-WebSocket-Key:", NULL,
  78. }
  79. };
  80. heads[3].val = &keyval[0];
  81. /* 16 bytes random */
  82. result = Curl_rand(data, (unsigned char *)rand, sizeof(rand));
  83. if(result)
  84. return result;
  85. result = Curl_base64_encode((char *)rand, sizeof(rand), &randstr, &randlen);
  86. if(result)
  87. return result;
  88. DEBUGASSERT(randlen < sizeof(keyval));
  89. if(randlen >= sizeof(keyval))
  90. return CURLE_FAILED_INIT;
  91. strcpy(keyval, randstr);
  92. free(randstr);
  93. for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) {
  94. if(!Curl_checkheaders(data, STRCONST(heads[i].name))) {
  95. #ifdef USE_HYPER
  96. char field[128];
  97. msnprintf(field, sizeof(field), "%s %s", heads[i].name,
  98. heads[i].val);
  99. result = Curl_hyper_header(data, req, field);
  100. #else
  101. (void)data;
  102. result = Curl_dyn_addf(req, "%s %s\r\n", heads[i].name,
  103. heads[i].val);
  104. #endif
  105. }
  106. }
  107. k->upgr101 = UPGR101_WS;
  108. Curl_dyn_init(&data->req.p.http->ws.buf, MAX_WS_SIZE * 2);
  109. return result;
  110. }
  111. CURLcode Curl_ws_accept(struct Curl_easy *data)
  112. {
  113. struct SingleRequest *k = &data->req;
  114. struct HTTP *ws = data->req.p.http;
  115. struct connectdata *conn = data->conn;
  116. struct websocket *wsp = &data->req.p.http->ws;
  117. CURLcode result;
  118. /* Verify the Sec-WebSocket-Accept response.
  119. The sent value is the base64 encoded version of a SHA-1 hash done on the
  120. |Sec-WebSocket-Key| header field concatenated with
  121. the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".
  122. */
  123. /* If the response includes a |Sec-WebSocket-Extensions| header field and
  124. this header field indicates the use of an extension that was not present
  125. in the client's handshake (the server has indicated an extension not
  126. requested by the client), the client MUST Fail the WebSocket Connection.
  127. */
  128. /* If the response includes a |Sec-WebSocket-Protocol| header field
  129. and this header field indicates the use of a subprotocol that was
  130. not present in the client's handshake (the server has indicated a
  131. subprotocol not requested by the client), the client MUST Fail
  132. the WebSocket Connection. */
  133. /* 4 bytes random */
  134. result = Curl_rand(data, (unsigned char *)&ws->ws.mask, sizeof(ws->ws.mask));
  135. if(result)
  136. return result;
  137. infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x",
  138. ws->ws.mask[0], ws->ws.mask[1], ws->ws.mask[2], ws->ws.mask[3]);
  139. k->upgr101 = UPGR101_RECEIVED;
  140. if(data->set.connect_only)
  141. /* switch off non-blocking sockets */
  142. (void)curlx_nonblock(conn->sock[FIRSTSOCKET], FALSE);
  143. wsp->oleft = 0;
  144. return result;
  145. }
  146. #define WSBIT_FIN 0x80
  147. #define WSBIT_OPCODE_CONT 0
  148. #define WSBIT_OPCODE_TEXT (1)
  149. #define WSBIT_OPCODE_BIN (2)
  150. #define WSBIT_OPCODE_CLOSE (8)
  151. #define WSBIT_OPCODE_PING (9)
  152. #define WSBIT_OPCODE_PONG (0xa)
  153. #define WSBIT_OPCODE_MASK (0xf)
  154. #define WSBIT_MASK 0x80
  155. /* remove the spent bytes from the beginning of the buffer as that part has
  156. now been delivered to the application */
  157. static void ws_decode_clear(struct Curl_easy *data)
  158. {
  159. struct websocket *wsp = &data->req.p.http->ws;
  160. size_t spent = wsp->usedbuf;
  161. size_t len = Curl_dyn_len(&wsp->buf);
  162. size_t keep = len - spent;
  163. DEBUGASSERT(len >= spent);
  164. Curl_dyn_tail(&wsp->buf, keep);
  165. }
  166. /* ws_decode() decodes a binary frame into structured WebSocket data,
  167. wpkt - the incoming raw data. If NULL, work on the already buffered data.
  168. ilen - the size of the provided data, perhaps too little, perhaps too much
  169. out - stored pointed to extracted data
  170. olen - stored length of the extracted data
  171. oleft - number of unread bytes pending to that belongs to this frame
  172. endp - stored pointer to data immediately following the parsed data, if
  173. there is more data in there. NULL if there's no more data.
  174. flags - stored bitmask about the frame
  175. Returns CURLE_AGAIN if there is only a partial frame in the buffer. Then it
  176. stores the first part in the ->extra buffer to be used in the next call
  177. when more data is provided.
  178. */
  179. static CURLcode ws_decode(struct Curl_easy *data,
  180. unsigned char *wpkt, size_t ilen,
  181. unsigned char **out, size_t *olen,
  182. curl_off_t *oleft,
  183. unsigned char **endp,
  184. unsigned int *flags)
  185. {
  186. bool fin;
  187. unsigned char opcode;
  188. curl_off_t total;
  189. size_t dataindex = 2;
  190. curl_off_t plen; /* size of data in the buffer */
  191. curl_off_t payloadsize;
  192. struct websocket *wsp = &data->req.p.http->ws;
  193. unsigned char *p;
  194. CURLcode result;
  195. *olen = 0;
  196. /* add the incoming bytes, if any */
  197. if(wpkt) {
  198. result = Curl_dyn_addn(&wsp->buf, wpkt, ilen);
  199. if(result)
  200. return result;
  201. }
  202. plen = Curl_dyn_len(&wsp->buf);
  203. if(plen < 2) {
  204. /* the smallest possible frame is two bytes */
  205. infof(data, "WS: plen == %u, EAGAIN", (int)plen);
  206. return CURLE_AGAIN;
  207. }
  208. p = Curl_dyn_uptr(&wsp->buf);
  209. fin = p[0] & WSBIT_FIN;
  210. opcode = p[0] & WSBIT_OPCODE_MASK;
  211. infof(data, "WS:%d received FIN bit %u", __LINE__, (int)fin);
  212. *flags = 0;
  213. switch(opcode) {
  214. case WSBIT_OPCODE_CONT:
  215. if(!fin)
  216. *flags |= CURLWS_CONT;
  217. infof(data, "WS: received OPCODE CONT");
  218. break;
  219. case WSBIT_OPCODE_TEXT:
  220. infof(data, "WS: received OPCODE TEXT");
  221. *flags |= CURLWS_TEXT;
  222. break;
  223. case WSBIT_OPCODE_BIN:
  224. infof(data, "WS: received OPCODE BINARY");
  225. *flags |= CURLWS_BINARY;
  226. break;
  227. case WSBIT_OPCODE_CLOSE:
  228. infof(data, "WS: received OPCODE CLOSE");
  229. *flags |= CURLWS_CLOSE;
  230. break;
  231. case WSBIT_OPCODE_PING:
  232. infof(data, "WS: received OPCODE PING");
  233. *flags |= CURLWS_PING;
  234. break;
  235. case WSBIT_OPCODE_PONG:
  236. infof(data, "WS: received OPCODE PONG");
  237. *flags |= CURLWS_PONG;
  238. break;
  239. }
  240. if(p[1] & WSBIT_MASK) {
  241. /* A client MUST close a connection if it detects a masked frame. */
  242. failf(data, "WS: masked input frame");
  243. return CURLE_RECV_ERROR;
  244. }
  245. payloadsize = p[1];
  246. if(payloadsize == 126) {
  247. if(plen < 4) {
  248. infof(data, "WS:%d plen == %u, EAGAIN", __LINE__, (int)plen);
  249. return CURLE_AGAIN; /* not enough data available */
  250. }
  251. payloadsize = (p[2] << 8) | p[3];
  252. dataindex += 2;
  253. }
  254. else if(payloadsize == 127) {
  255. /* 64 bit payload size */
  256. if(plen < 10)
  257. return CURLE_AGAIN;
  258. if(p[2] & 80) {
  259. failf(data, "WS: too large frame");
  260. return CURLE_RECV_ERROR;
  261. }
  262. dataindex += 8;
  263. payloadsize = ((curl_off_t)p[2] << 56) |
  264. (curl_off_t)p[3] << 48 |
  265. (curl_off_t)p[4] << 40 |
  266. (curl_off_t)p[5] << 32 |
  267. (curl_off_t)p[6] << 24 |
  268. (curl_off_t)p[7] << 16 |
  269. (curl_off_t)p[8] << 8 |
  270. p[9];
  271. }
  272. total = dataindex + payloadsize;
  273. if(total > plen) {
  274. /* deliver a partial frame */
  275. *oleft = total - dataindex;
  276. payloadsize = total - dataindex;
  277. }
  278. else
  279. *oleft = 0;
  280. /* point to the payload */
  281. *out = &p[dataindex];
  282. /* return the payload length */
  283. *olen = payloadsize;
  284. wsp->usedbuf = total; /* number of bytes "used" from the buffer */
  285. *endp = &p[total];
  286. infof(data, "WS: received %zu bytes payload (%zu left)",
  287. payloadsize, *oleft);
  288. return CURLE_OK;
  289. }
  290. /* Curl_ws_writecb() is the write callback for websocket traffic. The
  291. websocket data is provided to this raw, in chunks. This function should
  292. handle/decode the data and call the "real" underlying callback accordingly.
  293. */
  294. size_t Curl_ws_writecb(char *buffer, size_t size /* 1 */,
  295. size_t nitems, void *userp)
  296. {
  297. struct HTTP *ws = (struct HTTP *)userp;
  298. struct Curl_easy *data = ws->ws.data;
  299. void *writebody_ptr = data->set.out;
  300. if(data->set.ws_raw_mode)
  301. return data->set.fwrite_func(buffer, size, nitems, writebody_ptr);
  302. else if(nitems) {
  303. unsigned char *frame = NULL;
  304. size_t flen = 0;
  305. CURLcode result;
  306. unsigned char *endp;
  307. curl_off_t oleft;
  308. decode:
  309. oleft = ws->ws.frame.bytesleft;
  310. if(!oleft) {
  311. unsigned int recvflags;
  312. result = ws_decode(data, (unsigned char *)buffer, nitems,
  313. &frame, &flen, &oleft, &endp, &recvflags);
  314. if(result == CURLE_AGAIN)
  315. /* insufficient amount of data, keep it for later */
  316. return nitems;
  317. else if(result) {
  318. infof(data, "WS: decode error %d", (int)result);
  319. return nitems - 1;
  320. }
  321. /* Store details about the frame to be reachable with curl_ws_meta()
  322. from within the write callback */
  323. ws->ws.frame.age = 0;
  324. ws->ws.frame.offset = 0;
  325. ws->ws.frame.flags = recvflags;
  326. ws->ws.frame.bytesleft = oleft;
  327. }
  328. else {
  329. if(nitems > (size_t)ws->ws.frame.bytesleft) {
  330. nitems = ws->ws.frame.bytesleft;
  331. endp = (unsigned char *)&buffer[nitems];
  332. }
  333. else
  334. endp = NULL;
  335. ws->ws.frame.offset += nitems;
  336. ws->ws.frame.bytesleft -= nitems;
  337. frame = (unsigned char *)buffer;
  338. flen = nitems;
  339. }
  340. if((ws->ws.frame.flags & CURLWS_PING) && !oleft) {
  341. /* auto-respond to PINGs, only works for single-frame payloads atm */
  342. size_t bytes;
  343. infof(data, "WS: auto-respond to PING with a PONG");
  344. DEBUGASSERT(frame);
  345. /* send back the exact same content as a PONG */
  346. result = curl_ws_send(data, frame, flen, &bytes, 0, CURLWS_PONG);
  347. if(result)
  348. return result;
  349. }
  350. else {
  351. /* deliver the decoded frame to the user callback */
  352. if(data->set.fwrite_func((char *)frame, 1, flen, writebody_ptr) != flen)
  353. return 0;
  354. }
  355. if(oleft)
  356. ws->ws.frame.offset += flen;
  357. /* the websocket frame has been delivered */
  358. ws_decode_clear(data);
  359. if(endp) {
  360. /* there's more websocket data to deal with in the buffer */
  361. buffer = NULL; /* don't pass in the data again */
  362. goto decode;
  363. }
  364. }
  365. return nitems;
  366. }
  367. CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
  368. size_t buflen, size_t *nread,
  369. struct curl_ws_frame **metap)
  370. {
  371. size_t bytes;
  372. CURLcode result;
  373. struct websocket *wsp = &data->req.p.http->ws;
  374. *nread = 0;
  375. *metap = NULL;
  376. /* get a download buffer */
  377. result = Curl_preconnect(data);
  378. if(result)
  379. return result;
  380. do {
  381. bool drain = FALSE; /* if there is pending buffered data to drain */
  382. char *inbuf = data->state.buffer;
  383. bytes = wsp->stillbuffer;
  384. if(!bytes) {
  385. result = curl_easy_recv(data, data->state.buffer,
  386. data->set.buffer_size, &bytes);
  387. if(result)
  388. return result;
  389. }
  390. else {
  391. /* the pending bytes can be found here */
  392. inbuf = wsp->stillb;
  393. drain = TRUE;
  394. }
  395. if(bytes) {
  396. unsigned char *out;
  397. size_t olen;
  398. unsigned char *endp;
  399. unsigned int recvflags;
  400. curl_off_t oleft = wsp->frame.bytesleft;
  401. infof(data, "WS: got %u websocket bytes to decode", (int)bytes);
  402. if(!oleft && !drain) {
  403. result = ws_decode(data, (unsigned char *)inbuf, bytes,
  404. &out, &olen, &oleft, &endp, &recvflags);
  405. if(result == CURLE_AGAIN)
  406. /* a packet fragment only */
  407. break;
  408. else if(result)
  409. return result;
  410. wsp->frame.offset = 0;
  411. wsp->frame.bytesleft = oleft;
  412. wsp->frame.flags = recvflags;
  413. }
  414. else {
  415. olen = oleft;
  416. out = (unsigned char *)wsp->stillb;
  417. recvflags = wsp->frame.flags;
  418. if((curl_off_t)buflen < oleft)
  419. /* there is still data left after this */
  420. wsp->frame.bytesleft -= buflen;
  421. else
  422. wsp->frame.bytesleft = 0;
  423. }
  424. /* auto-respond to PINGs */
  425. if((recvflags & CURLWS_PING) && !oleft) {
  426. infof(data, "WS: auto-respond to PING with a PONG");
  427. /* send back the exact same content as a PONG */
  428. result = curl_ws_send(data, out, olen, &bytes, 0, CURLWS_PONG);
  429. if(result)
  430. return result;
  431. }
  432. else {
  433. if(olen < buflen) {
  434. /* copy the payload to the user buffer */
  435. memcpy(buffer, out, olen);
  436. *nread = olen;
  437. if(!oleft)
  438. /* websocket frame has been delivered */
  439. ws_decode_clear(data);
  440. }
  441. else {
  442. /* copy a partial payload */
  443. memcpy(buffer, out, buflen);
  444. *nread = buflen;
  445. /* remember what is left and where */
  446. wsp->stillbuffer = olen - buflen;
  447. wsp->stillb = (char *)buffer + buflen;
  448. }
  449. wsp->frame.offset += *nread;
  450. }
  451. }
  452. else
  453. *nread = bytes;
  454. break;
  455. } while(1);
  456. *metap = &wsp->frame;
  457. return CURLE_OK;
  458. }
  459. static void ws_xor(struct Curl_easy *data,
  460. const unsigned char *source,
  461. unsigned char *dest,
  462. size_t len)
  463. {
  464. struct websocket *wsp = &data->req.p.http->ws;
  465. size_t i;
  466. /* append payload after the mask, XOR appropriately */
  467. for(i = 0; i < len; i++) {
  468. dest[i] = source[i] ^ wsp->mask[wsp->xori];
  469. wsp->xori++;
  470. wsp->xori &= 3;
  471. }
  472. }
  473. /***
  474. RFC 6455 Section 5.2
  475. 0 1 2 3
  476. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  477. +-+-+-+-+-------+-+-------------+-------------------------------+
  478. |F|R|R|R| opcode|M| Payload len | Extended payload length |
  479. |I|S|S|S| (4) |A| (7) | (16/64) |
  480. |N|V|V|V| |S| | (if payload len==126/127) |
  481. | |1|2|3| |K| | |
  482. +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
  483. | Extended payload length continued, if payload len == 127 |
  484. + - - - - - - - - - - - - - - - +-------------------------------+
  485. | |Masking-key, if MASK set to 1 |
  486. +-------------------------------+-------------------------------+
  487. | Masking-key (continued) | Payload Data |
  488. +-------------------------------- - - - - - - - - - - - - - - - +
  489. : Payload Data continued ... :
  490. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
  491. | Payload Data continued ... |
  492. +---------------------------------------------------------------+
  493. */
  494. static size_t ws_packethead(struct Curl_easy *data,
  495. size_t len, unsigned int flags)
  496. {
  497. struct HTTP *ws = data->req.p.http;
  498. unsigned char *out = (unsigned char *)data->state.ulbuf;
  499. unsigned char firstbyte = 0;
  500. int outi;
  501. unsigned char opcode;
  502. if(flags & CURLWS_TEXT) {
  503. opcode = WSBIT_OPCODE_TEXT;
  504. infof(data, "WS: send OPCODE TEXT");
  505. }
  506. else if(flags & CURLWS_CLOSE) {
  507. opcode = WSBIT_OPCODE_CLOSE;
  508. infof(data, "WS: send OPCODE CLOSE");
  509. }
  510. else if(flags & CURLWS_PING) {
  511. opcode = WSBIT_OPCODE_PING;
  512. infof(data, "WS: send OPCODE PING");
  513. }
  514. else if(flags & CURLWS_PONG) {
  515. opcode = WSBIT_OPCODE_PONG;
  516. infof(data, "WS: send OPCODE PONG");
  517. }
  518. else {
  519. opcode = WSBIT_OPCODE_BIN;
  520. infof(data, "WS: send OPCODE BINARY");
  521. }
  522. if(!(flags & CURLWS_CONT)) {
  523. /* if not marked as continuing, assume this is the final fragment */
  524. firstbyte |= WSBIT_FIN | opcode;
  525. ws->ws.contfragment = FALSE;
  526. }
  527. else if(ws->ws.contfragment) {
  528. /* the previous fragment was not a final one and this isn't either, keep a
  529. CONT opcode and no FIN bit */
  530. firstbyte |= WSBIT_OPCODE_CONT;
  531. }
  532. else {
  533. ws->ws.contfragment = TRUE;
  534. }
  535. out[0] = firstbyte;
  536. if(len > 65535) {
  537. out[1] = 127 | WSBIT_MASK;
  538. out[2] = (len >> 8) & 0xff;
  539. out[3] = len & 0xff;
  540. outi = 10;
  541. }
  542. else if(len > 126) {
  543. out[1] = 126 | WSBIT_MASK;
  544. out[2] = (len >> 8) & 0xff;
  545. out[3] = len & 0xff;
  546. outi = 4;
  547. }
  548. else {
  549. out[1] = (unsigned char)len | WSBIT_MASK;
  550. outi = 2;
  551. }
  552. infof(data, "WS: send FIN bit %u (byte %02x)",
  553. firstbyte & WSBIT_FIN ? 1 : 0,
  554. firstbyte);
  555. infof(data, "WS: send payload len %u", (int)len);
  556. /* 4 bytes mask */
  557. memcpy(&out[outi], &ws->ws.mask, 4);
  558. if(data->set.upload_buffer_size < (len + 10))
  559. return 0;
  560. /* pass over the mask */
  561. outi += 4;
  562. ws->ws.xori = 0;
  563. /* return packet size */
  564. return outi;
  565. }
  566. CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer,
  567. size_t buflen, size_t *sent,
  568. curl_off_t totalsize,
  569. unsigned int sendflags)
  570. {
  571. CURLcode result;
  572. size_t headlen;
  573. char *out;
  574. ssize_t written;
  575. struct websocket *wsp = &data->req.p.http->ws;
  576. if(!data->set.ws_raw_mode) {
  577. result = Curl_get_upload_buffer(data);
  578. if(result)
  579. return result;
  580. }
  581. else {
  582. if(totalsize || sendflags)
  583. return CURLE_BAD_FUNCTION_ARGUMENT;
  584. }
  585. if(data->set.ws_raw_mode) {
  586. if(!buflen)
  587. /* nothing to do */
  588. return CURLE_OK;
  589. /* raw mode sends exactly what was requested, and this is from within
  590. the write callback */
  591. if(Curl_is_in_callback(data))
  592. result = Curl_write(data, data->conn->writesockfd, buffer, buflen,
  593. &written);
  594. else
  595. result = Curl_senddata(data, buffer, buflen, &written);
  596. infof(data, "WS: wanted to send %zu bytes, sent %zu bytes",
  597. buflen, written);
  598. *sent = written;
  599. return result;
  600. }
  601. if(buflen > (data->set.upload_buffer_size - 10))
  602. /* don't do more than this in one go */
  603. buflen = data->set.upload_buffer_size - 10;
  604. if(sendflags & CURLWS_OFFSET) {
  605. if(totalsize) {
  606. /* a frame series 'totalsize' bytes big, this is the first */
  607. headlen = ws_packethead(data, totalsize, sendflags);
  608. wsp->sleft = totalsize - buflen;
  609. }
  610. else {
  611. headlen = 0;
  612. if((curl_off_t)buflen > wsp->sleft) {
  613. infof(data, "WS: unaligned frame size (sending %zu instead of %zu)",
  614. buflen, wsp->sleft);
  615. wsp->sleft = 0;
  616. }
  617. else
  618. wsp->sleft -= buflen;
  619. }
  620. }
  621. else
  622. headlen = ws_packethead(data, buflen, sendflags);
  623. /* headlen is the size of the frame header */
  624. out = data->state.ulbuf;
  625. if(buflen)
  626. /* for PING and PONG etc there might not be a payload */
  627. ws_xor(data, buffer, (unsigned char *)out + headlen, buflen - headlen);
  628. if(Curl_is_in_callback(data))
  629. result = Curl_write(data, data->conn->writesockfd, out,
  630. buflen + headlen, &written);
  631. else
  632. result = Curl_senddata(data, out, buflen + headlen, &written);
  633. infof(data, "WS: wanted to send %zu bytes, sent %zu bytes",
  634. headlen + buflen, written);
  635. *sent = written;
  636. return result;
  637. }
  638. void Curl_ws_done(struct Curl_easy *data)
  639. {
  640. struct websocket *wsp = &data->req.p.http->ws;
  641. DEBUGASSERT(wsp);
  642. Curl_dyn_free(&wsp->buf);
  643. }
  644. CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
  645. {
  646. /* we only return something for websocket, called from within the callback
  647. when not using raw mode */
  648. if(GOOD_EASY_HANDLE(data) && Curl_is_in_callback(data) && data->req.p.http &&
  649. !data->set.ws_raw_mode)
  650. return &data->req.p.http->ws.frame;
  651. return NULL;
  652. }
  653. #else
  654. CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
  655. size_t *nread,
  656. struct curl_ws_frame **metap)
  657. {
  658. (void)curl;
  659. (void)buffer;
  660. (void)buflen;
  661. (void)nread;
  662. (void)metap;
  663. return CURLE_OK;
  664. }
  665. CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
  666. size_t buflen, size_t *sent,
  667. curl_off_t framesize,
  668. unsigned int sendflags)
  669. {
  670. (void)curl;
  671. (void)buffer;
  672. (void)buflen;
  673. (void)sent;
  674. (void)framesize;
  675. (void)sendflags;
  676. return CURLE_OK;
  677. }
  678. CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
  679. {
  680. (void)data;
  681. return NULL;
  682. }
  683. #endif /* USE_WEBSOCKETS */