349
376
char *recvBytes = recvData;
350
377
WaitressFetchBufCbBuffer_t *buffer = extraData;
352
if (buffer->buf == NULL) {
353
if ((buffer->buf = malloc (sizeof (*buffer->buf) *
379
if (buffer->data == NULL) {
380
if ((buffer->data = malloc (sizeof (*buffer->data) *
354
381
(recvDataSize + 1))) == NULL) {
355
382
return WAITRESS_CB_RET_ERR;
359
if ((newbuf = realloc (buffer->buf,
360
sizeof (*buffer->buf) *
386
if ((newbuf = realloc (buffer->data,
387
sizeof (*buffer->data) *
361
388
(buffer->pos + recvDataSize + 1))) == NULL) {
363
390
return WAITRESS_CB_RET_ERR;
365
buffer->buf = newbuf;
392
buffer->data = newbuf;
367
memcpy (buffer->buf + buffer->pos, recvBytes, recvDataSize);
394
memcpy (buffer->data + buffer->pos, recvBytes, recvDataSize);
368
395
buffer->pos += recvDataSize;
369
*(buffer->buf+buffer->pos) = '\0';
396
buffer->data[buffer->pos] = '\0';
371
398
return WAITRESS_CB_RET_OK;
374
401
/* Fetch string. Beware! This overwrites your waith->data pointer
375
402
* @param waitress handle
376
* @param result buffer, malloced (don't forget to free it yourself)
403
* @param \0-terminated result buffer, malloced (don't forget to free it
378
WaitressReturn_t WaitressFetchBuf (WaitressHandle_t *waith, char **buf) {
406
WaitressReturn_t WaitressFetchBuf (WaitressHandle_t *waith, char **retBuffer) {
379
407
WaitressFetchBufCbBuffer_t buffer;
380
408
WaitressReturn_t wRet;
410
assert (waith != NULL);
411
assert (retBuffer != NULL);
382
413
memset (&buffer, 0, sizeof (buffer));
384
415
waith->data = &buffer;
385
416
waith->callback = WaitressFetchBufCb;
387
418
wRet = WaitressFetchCall (waith);
419
*retBuffer = buffer.data;
392
423
/* poll wrapper that retries after signal interrupts, required for socksify
395
static int WaitressPollLoop (struct pollfd *fds, nfds_t nfds, int timeout) {
426
static int WaitressPollLoop (int fd, short events, int timeout) {
396
427
int pollres = -1;
428
struct pollfd sockpoll = {fd, events, 0};
400
pollres = poll (fds, nfds, timeout);
403
} while (pollerr == EINTR || pollerr == EINPROGRESS || pollerr == EAGAIN);
434
pollres = poll (&sockpoll, 1, timeout);
435
} while (errno == EINTR || errno == EINPROGRESS || errno == EAGAIN);
408
440
/* write () wrapper with poll () timeout
441
* @param waitress handle
410
442
* @param write buffer
411
443
* @param write count bytes
412
* @param reuse existing pollfd structure
413
* @param timeout (microseconds)
414
* @return WAITRESS_RET_OK, WAITRESS_RET_TIMEOUT or WAITRESS_RET_ERR
444
* @return number of written bytes or -1 on error
416
static WaitressReturn_t WaitressPollWrite (int sockfd, const char *buf, size_t count,
417
struct pollfd *sockpoll, int timeout) {
446
static ssize_t WaitressPollWrite (WaitressHandle_t *waith,
447
const char *buf, size_t count) {
418
448
int pollres = -1;
420
sockpoll->events = POLLOUT;
421
pollres = WaitressPollLoop (sockpoll, 1, timeout);
451
assert (waith != NULL);
452
assert (buf != NULL);
454
/* FIXME: simplify logic */
455
pollres = WaitressPollLoop (waith->request.sockfd, POLLOUT,
422
457
if (pollres == 0) {
423
return WAITRESS_RET_TIMEOUT;
458
waith->request.readWriteRet = WAITRESS_RET_TIMEOUT;
424
460
} else if (pollres == -1) {
425
return WAITRESS_RET_ERR;
427
if (write (sockfd, buf, count) == -1) {
428
return WAITRESS_RET_ERR;
430
return WAITRESS_RET_OK;
461
waith->request.readWriteRet = WAITRESS_RET_ERR;
464
if ((retSize = write (waith->request.sockfd, buf, count)) == -1) {
465
waith->request.readWriteRet = WAITRESS_RET_ERR;
468
waith->request.readWriteRet = WAITRESS_RET_OK;
472
static WaitressReturn_t WaitressOrdinaryWrite (WaitressHandle_t *waith,
473
const char *buf, const size_t size) {
474
WaitressPollWrite (waith, buf, size);
475
return waith->request.readWriteRet;
478
static WaitressReturn_t WaitressGnutlsWrite (WaitressHandle_t *waith,
479
const char *buf, const size_t size) {
480
if (gnutls_record_send (waith->request.tlsSession, buf, size) < 0) {
481
return WAITRESS_RET_TLS_WRITE_ERR;
483
return waith->request.readWriteRet;
433
486
/* read () wrapper with poll () timeout
487
* @param waitress handle
435
488
* @param write to this buf, not NULL terminated
436
489
* @param buffer size
437
* @param reuse existing pollfd struct
438
* @param timeout (in microseconds)
439
* @param read () return value/written bytes
440
* @return WAITRESS_RET_OK, WAITRESS_RET_TIMEOUT, WAITRESS_RET_ERR
490
* @return number of read bytes or -1 on error
442
static WaitressReturn_t WaitressPollRead (int sockfd, char *buf, size_t count,
443
struct pollfd *sockpoll, int timeout, ssize_t *retSize) {
492
static ssize_t WaitressPollRead (WaitressHandle_t *waith, char *buf,
444
494
int pollres = -1;
446
sockpoll->events = POLLIN;
447
pollres = WaitressPollLoop (sockpoll, 1, timeout);
497
assert (waith != NULL);
498
assert (buf != NULL);
500
/* FIXME: simplify logic */
501
pollres = WaitressPollLoop (waith->request.sockfd, POLLIN, waith->timeout);
448
502
if (pollres == 0) {
449
return WAITRESS_RET_TIMEOUT;
503
waith->request.readWriteRet = WAITRESS_RET_TIMEOUT;
450
505
} else if (pollres == -1) {
451
return WAITRESS_RET_ERR;
453
if ((*retSize = read (sockfd, buf, count)) == -1) {
454
return WAITRESS_RET_READ_ERR;
456
return WAITRESS_RET_OK;
459
/* FIXME: compiler macros are ugly... */
460
#define CLOSE_RET(ret) close (sockfd); return ret;
461
#define WRITE_RET(buf, count) \
462
if ((wRet = WaitressPollWrite (sockfd, buf, count, \
463
&sockpoll, waith->socktimeout)) != WAITRESS_RET_OK) { \
466
#define READ_RET(buf, count, size) \
467
if ((wRet = WaitressPollRead (sockfd, buf, count, \
468
&sockpoll, waith->socktimeout, size)) != WAITRESS_RET_OK) { \
506
waith->request.readWriteRet = WAITRESS_RET_ERR;
509
if ((retSize = read (waith->request.sockfd, buf, count)) == -1) {
510
waith->request.readWriteRet = WAITRESS_RET_READ_ERR;
513
waith->request.readWriteRet = WAITRESS_RET_OK;
517
static WaitressReturn_t WaitressOrdinaryRead (WaitressHandle_t *waith,
518
char *buf, const size_t size, size_t *retSize) {
519
const ssize_t ret = WaitressPollRead (waith, buf, size);
523
return waith->request.readWriteRet;
526
static WaitressReturn_t WaitressGnutlsRead (WaitressHandle_t *waith,
527
char *buf, const size_t size, size_t *retSize) {
528
ssize_t ret = gnutls_record_recv (waith->request.tlsSession, buf, size);
530
return WAITRESS_RET_TLS_READ_ERR;
534
return waith->request.readWriteRet;
472
537
/* send basic http authorization
473
538
* @param waitress handle
493
565
/* get default http port if none was given
495
static const char *WaitressDefaultPort (WaitressUrl_t *url) {
496
return url->port == NULL ? "80" : url->port;
499
/* Receive data from host and call *callback ()
500
* @param waitress handle
501
* @return WaitressReturn_t
503
WaitressReturn_t WaitressFetchCall (WaitressHandle_t *waith) {
567
static const char *WaitressDefaultPort (const WaitressUrl_t * const url) {
568
assert (url != NULL);
570
return url->port == NULL ? (url->tls ? "443" : "80") : url->port;
573
/* get line from string
574
* @param string beginning/return value of last call
575
* @return start of _next_ line or NULL if there is no next line
577
static char *WaitressGetline (char * const str) {
580
assert (str != NULL);
582
eol = strchr (str, '\n');
587
/* make lines parseable by string routines */
589
if (eol-1 >= str && *(eol-1) == '\r') {
600
/* identity encoding handler
602
static WaitressHandlerReturn_t WaitressHandleIdentity (WaitressHandle_t *waith,
603
char *buf, const size_t size) {
604
assert (waith != NULL);
605
assert (buf != NULL);
607
waith->request.contentReceived += size;
608
if (waith->callback (buf, size, waith->data) == WAITRESS_CB_RET_ERR) {
609
return WAITRESS_HANDLER_ABORTED;
611
return WAITRESS_HANDLER_CONTINUE;
615
/* chunked encoding handler. buf must be \0-terminated, size does not include
618
static WaitressHandlerReturn_t WaitressHandleChunked (WaitressHandle_t *waith,
619
char *buf, const size_t size) {
620
char *content = buf, *nextContent;
622
assert (waith != NULL);
623
assert (buf != NULL);
626
if (waith->request.chunkSize > 0) {
627
const size_t remaining = size-(content-buf);
629
if (remaining >= waith->request.chunkSize) {
630
if (WaitressHandleIdentity (waith, content,
631
waith->request.chunkSize) == WAITRESS_HANDLER_ABORTED) {
632
return WAITRESS_HANDLER_ABORTED;
635
content += waith->request.chunkSize;
636
if (content[0] == '\r' && content[1] == '\n') {
639
return WAITRESS_HANDLER_ERR;
641
waith->request.chunkSize = 0;
643
if (WaitressHandleIdentity (waith, content, remaining) ==
644
WAITRESS_HANDLER_ABORTED) {
645
return WAITRESS_HANDLER_ABORTED;
647
waith->request.chunkSize -= remaining;
648
return WAITRESS_HANDLER_CONTINUE;
652
if ((nextContent = WaitressGetline (content)) != NULL) {
653
const long int chunkSize = strtol (content, NULL, 16);
654
if (chunkSize == 0) {
655
return WAITRESS_HANDLER_DONE;
656
} else if (chunkSize < 0) {
657
return WAITRESS_HANDLER_ERR;
659
waith->request.chunkSize = chunkSize;
660
content = nextContent;
663
return WAITRESS_HANDLER_ERR;
668
return WAITRESS_HANDLER_ERR;
671
/* handle http header
673
static void WaitressHandleHeader (WaitressHandle_t *waith, const char * const key,
674
const char * const value) {
675
assert (waith != NULL);
676
assert (key != NULL);
677
assert (value != NULL);
679
if (strcaseeq (key, "Content-Length")) {
680
waith->request.contentLength = atol (value);
681
} else if (strcaseeq (key, "Transfer-Encoding")) {
682
if (strcaseeq (value, "chunked")) {
683
waith->request.dataHandler = WaitressHandleChunked;
688
/* parse http status line and return status code
690
static int WaitressParseStatusline (const char * const line) {
691
char status[4] = "000";
693
assert (line != NULL);
695
if (sscanf (line, "HTTP/1.%*1[0-9] %3[0-9] ", status) == 1) {
696
return atoi (status);
701
/* verify server certificate
703
static int WaitressTlsVerify (gnutls_session_t session) {
704
unsigned int status, certListSize;
705
const gnutls_datum_t *certList;
706
gnutls_x509_crt_t cert;
707
const WaitressHandle_t *waith;
709
waith = gnutls_session_get_ptr (session);
710
assert (waith != NULL);
712
if (gnutls_certificate_verify_peers2 (session, &status) != GNUTLS_E_SUCCESS) {
713
return GNUTLS_E_CERTIFICATE_ERROR;
716
/* don't accept invalid certs */
717
if (status & (GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND |
718
GNUTLS_CERT_REVOKED | GNUTLS_CERT_EXPIRED |
719
GNUTLS_CERT_NOT_ACTIVATED)) {
720
return GNUTLS_E_CERTIFICATE_ERROR;
723
if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
724
return GNUTLS_E_CERTIFICATE_ERROR;
728
if ((certList = gnutls_certificate_get_peers (session,
729
&certListSize)) == NULL) {
730
return GNUTLS_E_CERTIFICATE_ERROR;
733
if (gnutls_x509_crt_init (&cert) != GNUTLS_E_SUCCESS) {
734
return GNUTLS_E_CERTIFICATE_ERROR;
737
if (gnutls_x509_crt_import (cert, &certList[0],
738
GNUTLS_X509_FMT_DER) != GNUTLS_E_SUCCESS) {
739
return GNUTLS_E_CERTIFICATE_ERROR;
742
if (gnutls_x509_crt_check_hostname (cert, waith->url.host) == 0) {
743
return GNUTLS_E_CERTIFICATE_ERROR;
746
gnutls_x509_crt_deinit (cert);
753
static WaitressReturn_t WaitressConnect (WaitressHandle_t *waith) {
504
754
struct addrinfo hints, *res;
506
char recvBuf[WAITRESS_RECV_BUFFER];
507
char writeBuf[2*1024];
508
ssize_t recvSize = 0;
509
WaitressReturn_t wRet = WAITRESS_RET_OK;
510
struct pollfd sockpoll;
512
/* header parser vars */
513
char *nextLine = NULL, *thisLine = NULL;
514
enum {HDRM_HEAD, HDRM_LINES, HDRM_FINISHED} hdrParseMode = HDRM_HEAD;
515
char statusCode[3], val[256];
516
unsigned int bufFilled = 0;
519
waith->contentLength = 0;
520
waith->contentReceived = 0;
521
757
memset (&hints, 0, sizeof hints);
523
759
hints.ai_family = AF_UNSPEC;
539
if ((sockfd = socket (res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
775
if ((waith->request.sockfd = socket (res->ai_family, res->ai_socktype,
776
res->ai_protocol)) == -1) {
540
777
freeaddrinfo (res);
541
778
return WAITRESS_RET_SOCK_ERR;
543
sockpoll.fd = sockfd;
545
781
/* we need shorter timeouts for connect() */
546
fcntl (sockfd, F_SETFL, O_NONBLOCK);
782
fcntl (waith->request.sockfd, F_SETFL, O_NONBLOCK);
548
784
/* increase socket receive buffer */
549
785
const int sockopt = 256*1024;
550
setsockopt (sockfd, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof (sockopt));
786
setsockopt (waith->request.sockfd, SOL_SOCKET, SO_RCVBUF, &sockopt,
552
789
/* non-blocking connect will return immediately */
553
connect (sockfd, res->ai_addr, res->ai_addrlen);
790
connect (waith->request.sockfd, res->ai_addr, res->ai_addrlen);
555
sockpoll.events = POLLOUT;
556
pollres = WaitressPollLoop (&sockpoll, 1, waith->socktimeout);
792
pollres = WaitressPollLoop (waith->request.sockfd, POLLOUT,
557
794
freeaddrinfo (res);
558
795
if (pollres == 0) {
559
796
return WAITRESS_RET_TIMEOUT;
563
800
/* check connect () return value */
564
801
socklen_t pollresSize = sizeof (pollres);
565
getsockopt (sockfd, SOL_SOCKET, SO_ERROR, &pollres, &pollresSize);
802
getsockopt (waith->request.sockfd, SOL_SOCKET, SO_ERROR, &pollres,
566
804
if (pollres != 0) {
567
805
return WAITRESS_RET_CONNECT_REFUSED;
808
if (waith->url.tls) {
809
/* set up proxy tunnel */
810
if (WaitressProxyEnabled (waith)) {
813
snprintf (buf, sizeof (buf), "CONNECT %s:%s HTTP/"
814
WAITRESS_HTTP_VERSION "\r\n\r\n",
815
waith->url.host, WaitressDefaultPort (&waith->url));
816
WaitressOrdinaryWrite (waith, buf, strlen (buf));
818
WaitressOrdinaryRead (waith, buf, sizeof (buf)-1, &size);
820
if (WaitressParseStatusline (buf) != 200) {
821
return WAITRESS_RET_CONNECT_REFUSED;
825
if (gnutls_handshake (waith->request.tlsSession) != GNUTLS_E_SUCCESS) {
826
return WAITRESS_RET_TLS_HANDSHAKE_ERR;
830
return WAITRESS_RET_OK;
833
/* Write http header/post data to socket
835
static WaitressReturn_t WaitressSendRequest (WaitressHandle_t *waith) {
836
#define WRITE_RET(buf, count) \
837
if ((wRet = waith->request.write (waith, buf, count)) != WAITRESS_RET_OK) { \
841
assert (waith != NULL);
842
assert (waith->request.buf != NULL);
570
844
const char *path = waith->url.path;
845
char * const buf = waith->request.buf;
846
WaitressReturn_t wRet = WAITRESS_RET_OK;
571
848
if (waith->url.path == NULL) {
572
849
/* avoid NULL pointer deref */
579
856
/* send request */
580
if (WaitressProxyEnabled (waith)) {
581
snprintf (writeBuf, sizeof (writeBuf),
582
"%s http://%s:%s/%s HTTP/1.0\r\n",
857
if (WaitressProxyEnabled (waith) && !waith->url.tls) {
858
snprintf (buf, WAITRESS_BUFFER_SIZE,
859
"%s http://%s:%s/%s HTTP/" WAITRESS_HTTP_VERSION "\r\n",
583
860
(waith->method == WAITRESS_METHOD_GET ? "GET" : "POST"),
585
862
WaitressDefaultPort (&waith->url), path);
587
snprintf (writeBuf, sizeof (writeBuf),
588
"%s /%s HTTP/1.0\r\n",
864
snprintf (buf, WAITRESS_BUFFER_SIZE,
865
"%s /%s HTTP/" WAITRESS_HTTP_VERSION "\r\n",
589
866
(waith->method == WAITRESS_METHOD_GET ? "GET" : "POST"),
592
WRITE_RET (writeBuf, strlen (writeBuf));
869
WRITE_RET (buf, strlen (buf));
594
snprintf (writeBuf, sizeof (writeBuf),
595
"Host: %s\r\nUser-Agent: " PACKAGE "\r\n", waith->url.host);
596
WRITE_RET (writeBuf, strlen (writeBuf));
871
snprintf (buf, WAITRESS_BUFFER_SIZE,
872
"Host: %s\r\nUser-Agent: " PACKAGE "\r\nConnection: Close\r\n",
874
WRITE_RET (buf, strlen (buf));
598
876
if (waith->method == WAITRESS_METHOD_POST && waith->postData != NULL) {
599
snprintf (writeBuf, sizeof (writeBuf), "Content-Length: %zu\r\n",
877
snprintf (buf, WAITRESS_BUFFER_SIZE, "Content-Length: %zu\r\n",
600
878
strlen (waith->postData));
601
WRITE_RET (writeBuf, strlen (writeBuf));
879
WRITE_RET (buf, strlen (buf));
604
882
/* write authorization headers */
605
if (WaitressFormatAuthorization (waith, &waith->url, "", writeBuf,
606
sizeof (writeBuf))) {
607
WRITE_RET (writeBuf, strlen (writeBuf));
883
if (WaitressFormatAuthorization (waith, &waith->url, "", buf,
884
WAITRESS_BUFFER_SIZE)) {
885
WRITE_RET (buf, strlen (buf));
609
887
if (WaitressFormatAuthorization (waith, &waith->proxy, "Proxy-",
610
writeBuf, sizeof (writeBuf))) {
611
WRITE_RET (writeBuf, strlen (writeBuf));
888
buf, WAITRESS_BUFFER_SIZE)) {
889
WRITE_RET (buf, strlen (buf));
614
892
if (waith->extraHeaders != NULL) {
621
899
WRITE_RET (waith->postData, strlen (waith->postData));
902
return WAITRESS_RET_OK;
906
/* read response header and data
908
static WaitressReturn_t WaitressReceiveResponse (WaitressHandle_t *waith) {
909
#define READ_RET(buf, count, size) \
910
if ((wRet = waith->request.read (waith, buf, count, size)) != \
915
assert (waith != NULL);
916
assert (waith->request.buf != NULL);
918
char * const buf = waith->request.buf;
919
char *nextLine = NULL, *thisLine = NULL;
920
enum {HDRM_HEAD, HDRM_LINES, HDRM_FINISHED} hdrParseMode = HDRM_HEAD;
921
ssize_t recvSize = 0;
922
size_t bufFilled = 0;
923
WaitressReturn_t wRet = WAITRESS_RET_OK;
624
925
/* receive answer */
626
927
while (hdrParseMode != HDRM_FINISHED) {
627
READ_RET (recvBuf+bufFilled, sizeof (recvBuf)-1 - bufFilled, &recvSize);
928
READ_RET (buf+bufFilled, WAITRESS_BUFFER_SIZE-1 - bufFilled, &recvSize);
628
929
if (recvSize == 0) {
629
930
/* connection closed too early */
630
CLOSE_RET (WAITRESS_RET_CONNECTION_CLOSED);
931
return WAITRESS_RET_CONNECTION_CLOSED;
632
933
bufFilled += recvSize;
633
memset (recvBuf+bufFilled, 0, sizeof (recvBuf) - bufFilled);
934
buf[bufFilled] = '\0';
637
while ((nextLine = strchr (thisLine, '\n')) != NULL &&
638
hdrParseMode != HDRM_FINISHED) {
639
/* make lines parseable by string routines */
641
if (*(nextLine-1) == '\r') {
642
*(nextLine-1) = '\0';
938
while (hdrParseMode != HDRM_FINISHED &&
939
(nextLine = WaitressGetline (thisLine)) != NULL) {
647
940
switch (hdrParseMode) {
648
941
/* Status code */
650
if (sscanf (thisLine, "HTTP/1.%*1[0-9] %3[0-9] ",
652
if (memcmp (statusCode, "200", 3) == 0 ||
653
memcmp (statusCode, "206", 3) == 0) {
654
/* everything's fine... */
655
} else if (memcmp (statusCode, "403", 3) == 0) {
656
CLOSE_RET (WAITRESS_RET_FORBIDDEN);
657
} else if (memcmp (statusCode, "404", 3) == 0) {
658
CLOSE_RET (WAITRESS_RET_NOTFOUND);
660
CLOSE_RET (WAITRESS_RET_STATUS_UNKNOWN);
662
hdrParseMode = HDRM_LINES;
943
switch (WaitressParseStatusline (thisLine)) {
946
hdrParseMode = HDRM_LINES;
950
return WAITRESS_RET_FORBIDDEN;
954
return WAITRESS_RET_NOTFOUND;
958
/* ignore invalid line */
962
return WAITRESS_RET_STATUS_UNKNOWN;
666
967
/* Everything else, except status code */
681
989
} /* end switch */
682
990
thisLine = nextLine;
683
991
} /* end while strchr */
684
memmove (recvBuf, thisLine, thisLine-recvBuf);
685
bufFilled -= (thisLine-recvBuf);
992
memmove (buf, thisLine, bufFilled-(thisLine-buf));
993
bufFilled -= (thisLine-buf);
686
994
} /* end while hdrParseMode */
688
/* push remaining bytes */
690
waith->contentReceived += bufFilled;
691
if (waith->callback (thisLine, bufFilled, waith->data) ==
692
WAITRESS_CB_RET_ERR) {
693
CLOSE_RET (WAITRESS_RET_CB_ABORT);
697
/* receive content */
996
recvSize = bufFilled;
699
READ_RET (recvBuf, sizeof (recvBuf), &recvSize);
701
waith->contentReceived += recvSize;
702
if (waith->callback (recvBuf, recvSize, waith->data) ==
703
WAITRESS_CB_RET_ERR) {
704
wRet = WAITRESS_RET_CB_ABORT;
998
/* data must be \0-terminated for chunked handler */
999
buf[recvSize] = '\0';
1000
switch (waith->request.dataHandler (waith, buf, recvSize)) {
1001
case WAITRESS_HANDLER_DONE:
1002
return WAITRESS_RET_OK;
1005
case WAITRESS_HANDLER_ERR:
1006
return WAITRESS_RET_DECODING_ERR;
1009
case WAITRESS_HANDLER_ABORTED:
1010
return WAITRESS_RET_CB_ABORT;
1013
case WAITRESS_HANDLER_CONTINUE:
1017
READ_RET (buf, WAITRESS_BUFFER_SIZE-1, &recvSize);
708
1018
} while (recvSize > 0);
712
if (wRet == WAITRESS_RET_OK && waith->contentReceived < waith->contentLength) {
1020
return WAITRESS_RET_OK;
1025
/* Receive data from host and call *callback ()
1026
* @param waitress handle
1027
* @return WaitressReturn_t
1029
WaitressReturn_t WaitressFetchCall (WaitressHandle_t *waith) {
1030
WaitressReturn_t wRet = WAITRESS_RET_OK;
1033
memset (&waith->request, 0, sizeof (waith->request));
1034
waith->request.dataHandler = WaitressHandleIdentity;
1035
waith->request.read = WaitressOrdinaryRead;
1036
waith->request.write = WaitressOrdinaryWrite;
1038
if (waith->url.tls) {
1039
assert (waith->tlsInitialized);
1041
waith->request.read = WaitressGnutlsRead;
1042
waith->request.write = WaitressGnutlsWrite;
1043
gnutls_init (&waith->request.tlsSession, GNUTLS_CLIENT);
1045
if (gnutls_priority_set_direct (waith->request.tlsSession,
1046
"PERFORMANCE", &err) != GNUTLS_E_SUCCESS) {
1047
return WAITRESS_RET_ERR;
1049
if (gnutls_credentials_set (waith->request.tlsSession,
1050
GNUTLS_CRD_CERTIFICATE,
1051
waith->tlsCred) != GNUTLS_E_SUCCESS) {
1052
return WAITRESS_RET_ERR;
1055
/* set up custom read/write functions */
1056
gnutls_transport_set_ptr (waith->request.tlsSession,
1057
(gnutls_transport_ptr_t) waith);
1058
gnutls_transport_set_pull_function (waith->request.tlsSession,
1060
gnutls_transport_set_push_function (waith->request.tlsSession,
1063
/* certificate verification function */
1064
gnutls_session_set_ptr (waith->request.tlsSession,
1065
(gnutls_transport_ptr_t) waith);
1066
gnutls_certificate_set_verify_function (waith->tlsCred,
1071
if ((wRet = WaitressConnect (waith)) == WAITRESS_RET_OK) {
1072
waith->request.buf = malloc (WAITRESS_BUFFER_SIZE *
1073
sizeof (*waith->request.buf));
1075
if ((wRet = WaitressSendRequest (waith)) == WAITRESS_RET_OK) {
1076
wRet = WaitressReceiveResponse (waith);
1079
free (waith->request.buf);
1083
if (waith->url.tls) {
1084
gnutls_bye (waith->request.tlsSession, GNUTLS_SHUT_RDWR);
1085
gnutls_deinit (waith->request.tlsSession);
1087
close (waith->request.sockfd);
1089
if (wRet == WAITRESS_RET_OK &&
1090
waith->request.contentReceived < waith->request.contentLength) {
713
1091
return WAITRESS_RET_PARTIAL_FILE;
722
1096
const char *WaitressErrorToStr (WaitressReturn_t wRet) {
724
1098
case WAITRESS_RET_OK: