114#ifndef DISABLE_QHTTPCLIENT
123#include <sys/types.h>
124#include <sys/socket.h>
125#include <netinet/in.h>
126#include <netinet/tcp.h>
127#include <arpa/inet.h>
130#include "openssl/ssl.h"
131#include "openssl/err.h"
134#include "qinternal.h"
135#include "utilities/qio.h"
136#include "utilities/qstring.h"
137#include "utilities/qsocket.h"
138#include "containers/qlisttbl.h"
139#include "containers/qgrow.h"
140#include "extensions/qhttpclient.h"
144static bool open_(qhttpclient_t *client);
145static bool setssl(qhttpclient_t *client);
146static void settimeout(qhttpclient_t *client,
int timeoutms);
147static void setkeepalive(qhttpclient_t *client,
bool keepalive);
148static void setuseragent(qhttpclient_t *client,
const char *agentname);
150static bool head(qhttpclient_t *client,
const char *uri,
int *rescode,
151 qlisttbl_t *reqheaders, qlisttbl_t *resheaders);
152static bool get(qhttpclient_t *client,
const char *uri,
int fd, off_t *savesize,
153 int *rescode, qlisttbl_t *reqheaders, qlisttbl_t *resheaders,
154 bool (*callback)(
void *userdata, off_t recvbytes),
156static bool put(qhttpclient_t *client,
const char *uri,
int fd, off_t length,
157 int *rescode, qlisttbl_t *reqheaders, qlisttbl_t *resheaders,
158 bool (*callback)(
void *userdata, off_t sentbytes),
160static void *
cmd(qhttpclient_t *client,
const char *method,
const char *uri,
161 void *data,
size_t size,
int *rescode,
size_t *contentslength,
162 qlisttbl_t *reqheaders, qlisttbl_t *resheaders);
164static bool sendrequest(qhttpclient_t *client,
const char *method,
165 const char *uri, qlisttbl_t *reqheaders);
166static int readresponse(qhttpclient_t *client, qlisttbl_t *resheaders,
167 off_t *contentlength);
169static ssize_t
gets_(qhttpclient_t *client,
char *buf,
size_t bufsize);
170static ssize_t
read_(qhttpclient_t *client,
void *buf,
size_t nbytes);
171static ssize_t
write_(qhttpclient_t *client,
const void *buf,
size_t nbytes);
172static off_t
recvfile(qhttpclient_t *client,
int fd, off_t nbytes);
173static off_t
sendfile_(qhttpclient_t *client,
int fd, off_t nbytes);
175static bool _close(qhttpclient_t *client);
176static void _free(qhttpclient_t *client);
179static bool _set_socket_option(
int socket);
180static bool _parse_uri(
const char *uri,
bool *protocol,
char *hostname,
181 size_t namesize,
int *port);
188#define HTTP_NO_RESPONSE (0)
189#define HTTP_CODE_CONTINUE (100)
190#define HTTP_CODE_OK (200)
191#define HTTP_CODE_CREATED (201)
192#define HTTP_CODE_NO_CONTENT (204)
193#define HTTP_CODE_MULTI_STATUS (207)
194#define HTTP_CODE_MOVED_TEMPORARILY (302)
195#define HTTP_CODE_NOT_MODIFIED (304)
196#define HTTP_CODE_BAD_REQUEST (400)
197#define HTTP_CODE_FORBIDDEN (403)
198#define HTTP_CODE_NOT_FOUND (404)
199#define HTTP_CODE_METHOD_NOT_ALLOWED (405)
200#define HTTP_CODE_REQUEST_TIME_OUT (408)
201#define HTTP_CODE_REQUEST_URI_TOO_LONG (414)
202#define HTTP_CODE_INTERNAL_SERVER_ERROR (500)
203#define HTTP_CODE_NOT_IMPLEMENTED (501)
204#define HTTP_CODE_SERVICE_UNAVAILABLE (503)
206#define HTTP_PROTOCOL_11 "HTTP/1.1"
211#define SET_TCP_LINGER_TIMEOUT (15)
212#define SET_TCP_NODELAY (1)
213#define MAX_SHUTDOWN_WAIT (100)
214#define MAX_ATOMIC_DATA_SIZE (32 * 1024)
246 bool ishttps =
false;
248 if (port == 0 || strstr(destname,
"://") != NULL) {
249 if (_parse_uri(destname, &ishttps, hostname,
sizeof(hostname), &port)
251 DEBUG(
"Can't parse URI %s", destname);
255 DEBUG(
"https: %d, hostname: %s, port:%d\n", ishttps, hostname, port);
257 qstrcpy(hostname,
sizeof(hostname), destname);
261 struct sockaddr_in addr;
267 qhttpclient_t *client = (qhttpclient_t *) malloc(
sizeof(qhttpclient_t));
270 memset((
void *) client, 0,
sizeof(qhttpclient_t));
275 memcpy((
void *) &client->addr, (
void *) &addr,
sizeof(client->addr));
276 client->hostname = strdup(hostname);
285 client->open =
open_;
295 client->gets =
gets_;
296 client->read =
read_;
302 client->free =
_free;
323static bool setssl(qhttpclient_t *client) {
325 static bool initialized =
false;
327 if (client->socket >= 0) {
333 if (initialized ==
false) {
335 SSL_load_error_strings();
340 if (client->ssl == NULL) {
341 client->ssl = malloc(
sizeof(
struct SslConn));
342 if (client->ssl == NULL)
return false;
343 memset(client->ssl, 0,
sizeof(
struct SslConn));
363static void settimeout(qhttpclient_t *client,
int timeoutms) {
366 client->timeoutms = timeoutms;
381 client->keepalive = keepalive;
394static void setuseragent(qhttpclient_t *client,
const char *useragent) {
395 if (client->useragent != NULL)
396 free(client->useragent);
397 client->useragent = strdup(useragent);
417static bool open_(qhttpclient_t *client) {
418 if (client->socket >= 0) {
426 int sockfd = socket(AF_INET, SOCK_STREAM, 0);
428 DEBUG(
"sockfd creation failed.");
434 if (client->timeoutms > 0) {
435 sockflag = fcntl(sockfd, F_GETFL, 0);
436 fcntl(sockfd, F_SETFL, sockflag | O_NONBLOCK);
440 int status = connect(sockfd, (
struct sockaddr *) &client->addr,
441 sizeof(client->addr));
443 && (errno != EINPROGRESS
445 DEBUG(
"connection failed. (%d)", errno);
451 if (client->timeoutms > 0) {
452 fcntl(sockfd, F_SETFL, sockflag);
456 client->socket = sockfd;
459 _set_socket_option(sockfd);
463 if (client->ssl != NULL) {
465 struct SslConn *ssl = client->ssl;
466 ssl->ctx = SSL_CTX_new(SSLv23_client_method());
467 if (ssl->ctx == NULL) {
468 DEBUG(
"OpenSSL: %s", ERR_reason_error_string(ERR_get_error()));
474 ssl->ssl = SSL_new(ssl->ctx);
475 if (ssl->ssl == NULL) {
476 DEBUG(
"OpenSSL: %s", ERR_reason_error_string(ERR_get_error()));
482 if (SSL_set_fd(ssl->ssl, client->socket) != 1) {
483 DEBUG(
"OpenSSL: %s", ERR_reason_error_string(ERR_get_error()));
489 SSL_set_connect_state(ssl->ssl);
491#ifndef OPENSSL_NO_TLSEXT
493 ssl->ssl->tlsext_hostname = client->hostname;
497 if (SSL_connect(ssl->ssl) != 1) {
498 DEBUG(
"OpenSSL: %s", ERR_reason_error_string(ERR_get_error()));
503 DEBUG(
"ssl initialized");
558static bool head(qhttpclient_t *client,
const char *uri,
int *rescode,
559 qlisttbl_t *reqheaders, qlisttbl_t *resheaders) {
566 bool freeReqHeaders =
false;
567 if (reqheaders == NULL) {
569 QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
570 freeReqHeaders =
true;
574 reqheaders->putstr(reqheaders,
"Accept",
"*/*");
577 bool sendret =
sendrequest(client,
"HEAD", uri, reqheaders);
578 if (freeReqHeaders ==
true)
579 reqheaders->free(reqheaders);
580 if (sendret ==
false) {
593 if (
read_(client, NULL, clength) != clength) {
599 if (client->keepalive ==
false || client->connclose ==
true) {
603 if (resno == HTTP_CODE_OK)
694static bool get(qhttpclient_t *client,
const char *uri,
int fd, off_t *savesize,
695 int *rescode, qlisttbl_t *reqheaders, qlisttbl_t *resheaders,
696 bool (*callback)(
void *userdata, off_t recvbytes),
702 if (savesize != NULL)
706 bool freeReqHeaders =
false;
707 if (reqheaders == NULL) {
709 QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
710 freeReqHeaders =
true;
714 reqheaders->putstr(reqheaders,
"Accept",
"*/*");
717 bool sendret =
sendrequest(client,
"GET", uri, reqheaders);
718 if (freeReqHeaders ==
true)
719 reqheaders->free(reqheaders);
720 if (sendret ==
false) {
732 if (resno != HTTP_CODE_OK) {
735 if (
read_(client, NULL, clength) != clength) {
741 if (client->keepalive ==
false || client->connclose ==
true) {
749 if (callback != NULL && callback(userdata, recv) ==
false) {
755 while (recv < clength) {
756 unsigned int recvsize;
757 if (clength - recv < MAX_ATOMIC_DATA_SIZE) {
758 recvsize = clength - recv;
760 recvsize = MAX_ATOMIC_DATA_SIZE;
763 ssize_t ret =
recvfile(client, fd, recvsize);
767 if (savesize != NULL)
770 if (callback != NULL) {
771 if (callback(userdata, recv) ==
false) {
778 if (recv != clength) {
783 }
else if (clength == -1) {
784 bool completed =
false;
788 if (
gets_(client, buf,
sizeof(buf)) <= 0)
792 unsigned int recvsize;
793 if (sscanf(buf,
"%x", &recvsize) != 1) {
804 ssize_t ret =
recvfile(client, fd, recvsize);
808 DEBUG(
"%zd %zd", recv, ret);
809 if (savesize != NULL)
814 if (
gets_(client, buf,
sizeof(buf)) <= 0)
818 if (recvsize > 0 && callback != NULL
819 && callback(userdata, recv) ==
false) {
823 }
while (completed ==
false);
825 if (completed ==
false) {
826 DEBUG(
"Broken pipe. %jd/chunked, errno=%d", recv, errno);
833 if (client->keepalive ==
false || client->connclose ==
true) {
926static bool put(qhttpclient_t *client,
const char *uri,
int fd, off_t length,
927 int *rescode, qlisttbl_t *reqheaders, qlisttbl_t *resheaders,
928 bool (*callback)(
void *userdata, off_t sentbytes),
936 bool freeReqHeaders =
false;
937 if (reqheaders == NULL) {
939 QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
940 freeReqHeaders =
true;
944 reqheaders->putstrf(reqheaders,
"Content-Length",
"%jd", length);
945 reqheaders->putstr(reqheaders,
"Expect",
"100-continue");
948 bool sendret =
sendrequest(client,
"PUT", uri, reqheaders);
949 if (freeReqHeaders ==
true) {
950 reqheaders->free(reqheaders);
953 if (sendret ==
false) {
960 DEBUG(
"timed out %d", client->timeoutms);
968 if (resno != HTTP_CODE_CONTINUE) {
973 if (
read_(client, NULL, clength) != clength) {
979 if (client->keepalive ==
false || client->connclose ==
true) {
987 if (callback != NULL) {
988 if (callback(userdata, sent) ==
false) {
994 while (sent < length) {
996 if (length - sent < MAX_ATOMIC_DATA_SIZE)
997 sendsize = length - sent;
999 sendsize = MAX_ATOMIC_DATA_SIZE;
1001 ssize_t ret =
sendfile_(client, fd, sendsize);
1006 if (callback != NULL) {
1007 if (callback(userdata, sent) ==
false) {
1014 if (sent != length) {
1019 if (callback != NULL) {
1020 if (callback(userdata, sent) ==
false) {
1030 if (rescode != NULL)
1033 if (resno == HTTP_NO_RESPONSE) {
1039 if (
read_(client, NULL, clength) != clength) {
1045 if (client->keepalive ==
false || client->connclose ==
true) {
1049 if (resno == HTTP_CODE_CREATED)
1099static void *
cmd(qhttpclient_t *client,
const char *method,
const char *uri,
1100 void *data,
size_t size,
int *rescode,
size_t *contentslength,
1101 qlisttbl_t *reqheaders, qlisttbl_t *resheaders) {
1104 if (rescode != NULL)
1106 if (contentslength != NULL)
1107 *contentslength = 0;
1110 bool freeReqHeaders =
false;
1111 if (reqheaders == NULL && data != NULL && size > 0) {
1113 QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
1114 reqheaders->putstrf(reqheaders,
"Content-Length",
"%jd", size);
1115 freeReqHeaders =
true;
1118 bool sendret =
sendrequest(client, method, uri, reqheaders);
1119 if (freeReqHeaders ==
true) {
1120 reqheaders->free(reqheaders);
1123 if (sendret ==
false) {
1129 if (data != NULL && size > 0) {
1130 ssize_t written =
write_(client, data, size);
1131 if (written != size) {
1139 int resno =
readresponse(client, resheaders, &clength);
1140 if (rescode != NULL)
1142 if (contentslength != NULL)
1143 *contentslength = clength;
1146 void *content = NULL;
1148 content = malloc(clength + 1);
1149 if (content != NULL) {
1150 if (
read_(client, content, clength) == clength) {
1151 *(
char *) (content + clength) =
'\0';
1160 content = strdup(
"");
1164 if (client->keepalive ==
false || client->connclose ==
true) {
1195 const char *uri, qlisttbl_t *reqheaders) {
1196 if (
open_(client) ==
false) {
1201 bool freeReqHeaders =
false;
1202 if (reqheaders == NULL) {
1204 QLISTTBL_UNIQUE | QLISTTBL_CASEINSENSITIVE);
1205 if (reqheaders == NULL)
1207 freeReqHeaders =
true;
1211 if (reqheaders->get(reqheaders,
"Host", NULL,
false) == NULL) {
1212 reqheaders->putstrf(reqheaders,
"Host",
"%s:%d", client->hostname,
1215 if (reqheaders->get(reqheaders,
"User-Agent", NULL,
false) == NULL) {
1216 reqheaders->putstr(reqheaders,
"User-Agent", client->useragent);
1218 if (reqheaders->get(reqheaders,
"Connection", NULL,
false) == NULL) {
1220 reqheaders,
"Connection",
1221 (client->keepalive ==
true) ?
"Keep-Alive" :
"close");
1225 qgrow_t *outBuf =
qgrow(0);
1230 outBuf->addstrf(outBuf,
"%s %s %s\r\n", method, uri,
1235 memset((
void *) &obj, 0,
sizeof(obj));
1236 reqheaders->lock(reqheaders);
1237 while (reqheaders->getnext(reqheaders, &obj, NULL,
false) ==
true) {
1238 outBuf->addstrf(outBuf,
"%s: %s\r\n", obj.name, (
char *) obj.data);
1240 reqheaders->unlock(reqheaders);
1242 outBuf->addstrf(outBuf,
"\r\n");
1246 char *
final = outBuf->toarray(outBuf, &towrite);
1247 ssize_t written = 0;
1248 if (
final != NULL) {
1249 written =
write_(client,
final, towrite);
1254 outBuf->free(outBuf);
1255 if (freeReqHeaders ==
true)
1256 reqheaders->free(reqheaders);
1258 if (written > 0 && written == towrite)
1294 off_t *contentlength) {
1295 if (contentlength != NULL) {
1301 if (
gets_(client, buf,
sizeof(buf)) <= 0)
1302 return HTTP_NO_RESPONSE;
1305 if (strncmp(buf,
"HTTP/", CONST_STRLEN(
"HTTP/")))
1306 return HTTP_NO_RESPONSE;
1307 char *tmp = strstr(buf,
" ");
1309 return HTTP_NO_RESPONSE;
1310 int rescode = atoi(tmp + 1);
1312 return HTTP_NO_RESPONSE;
1315 while (
gets_(client, buf,
sizeof(buf)) > 0) {
1321 char *value = strstr(buf,
":");
1322 if (value != NULL) {
1331 if (resheaders != NULL) {
1332 resheaders->putstr(resheaders, name, value);
1336 if (!strcasecmp(name,
"Connection")) {
1337 if (!strcasecmp(value,
"close")) {
1338 client->connclose =
true;
1342 else if (contentlength != NULL && *contentlength == 0) {
1343 if (!strcasecmp(name,
"Content-Length")) {
1344 *contentlength = atoll(value);
1347 else if (!strcasecmp(name,
"Transfer-Encoding")
1348 && !strcasecmp(value,
"chunked")) {
1349 *contentlength = -1;
1372static ssize_t
gets_(qhttpclient_t *client,
char *buf,
size_t bufsize) {
1373#ifdef ENABLE_OPENSSL
1374 if (client->ssl == NULL) {
1375 return qio_gets(client->socket, buf, bufsize, client->timeoutms);
1377 if (bufsize <= 1)
return -1;
1379 struct SslConn *ssl = client->ssl;
1380 ssize_t readcnt = 0;
1383 for (ptr = buf; readcnt < (bufsize - 1); ptr++) {
1389 int rsize = SSL_read(ssl->ssl, ptr, 1);
1391 unsigned long sslerr = ERR_get_error();
1392 if (sslerr == SSL_ERROR_WANT_READ) {
1396 DEBUG(
"OpenSSL: %s (%d)",
1397 ERR_reason_error_string(sslerr), rsize);
1402 if (*ptr ==
'\r') ptr--;
1403 else if (*ptr ==
'\n')
break;
1407 DEBUG(
"SSL_read: %s (%zd)", buf, readcnt);
1409 if (readcnt > 0)
return readcnt;
1413 return qio_gets(client->socket, buf, bufsize, client->timeoutms);
1436static ssize_t
read_(qhttpclient_t *client,
void *buf,
size_t nbytes) {
1437#ifdef ENABLE_OPENSSL
1438 if (client->ssl == NULL) {
1439 return qio_read(client->socket, buf, nbytes, client->timeoutms);
1441 if (nbytes == 0)
return 0;
1443 struct SslConn *ssl = client->ssl;
1445 while (total < nbytes) {
1452 rsize = SSL_read(ssl->ssl, buf + total, nbytes - total);
1455 int toread = nbytes - total;
1456 if (toread >
sizeof(trash)) toread =
sizeof(trash);
1457 rsize = SSL_read(ssl->ssl, trash, toread);
1460 DEBUG(
"OpenSSL: %s (%d)",
1461 ERR_reason_error_string(ERR_get_error()), rsize);
1462 unsigned long sslerr = ERR_get_error();
1463 if (sslerr == SSL_ERROR_WANT_READ) {
1472 DEBUG(
"SSL_read: %zd", total);
1473 if (total > 0)
return total;
1477 return qio_read(client->socket, buf, nbytes, client->timeoutms);
1490static ssize_t
write_(qhttpclient_t *client,
const void *buf,
size_t nbytes) {
1491#ifdef ENABLE_OPENSSL
1492 if (client->ssl == NULL) {
1493 return qio_write(client->socket, buf, nbytes, -1);
1495 if (nbytes == 0)
return 0;
1497 struct SslConn *ssl = client->ssl;
1499 while (total < nbytes) {
1501 int wsize = SSL_write(ssl->ssl, buf + total, nbytes - total);
1503 DEBUG(
"OpenSSL: %s (%d)",
1504 ERR_reason_error_string(ERR_get_error()), wsize);
1505 unsigned long sslerr = ERR_get_error();
1506 if (sslerr == SSL_ERROR_WANT_WRITE) {
1515 DEBUG(
"SSL_write: %zd/%zu", total, nbytes);
1516 if (total > 0)
return total;
1520 return qio_write(client->socket, buf, nbytes, -1);
1534static off_t
recvfile(qhttpclient_t *client,
int fd, off_t nbytes) {
1538 unsigned char buf[MAX_ATOMIC_DATA_SIZE];
1541 while (total < nbytes) {
1543 if (nbytes - total <=
sizeof(buf))
1544 chunksize = nbytes - total;
1546 chunksize =
sizeof(buf);
1549 ssize_t rsize =
read_(client, buf, chunksize);
1554 ssize_t wsize =
qio_write(fd, buf, rsize, -1);
1555 DEBUG(
"FILE write: %zd", wsize);
1560 if (rsize != wsize) {
1561 DEBUG(
"size mismatch. read:%zd, write:%zd", rsize, wsize);
1580static off_t
sendfile_(qhttpclient_t *client,
int fd, off_t nbytes) {
1584 unsigned char buf[MAX_ATOMIC_DATA_SIZE];
1587 while (total < nbytes) {
1589 if (nbytes - total <=
sizeof(buf))
1590 chunksize = nbytes - total;
1592 chunksize =
sizeof(buf);
1595 ssize_t rsize =
qio_read(fd, buf, chunksize, -1);
1596 DEBUG(
"FILE read: %zd", rsize);
1601 ssize_t wsize =
write_(client, buf, rsize);
1606 if (rsize != wsize) {
1607 DEBUG(
"size mismatch. read:%zd, write:%zd", rsize, wsize);
1629 if (client->socket < 0)
1632#ifdef ENABLE_OPENSSL
1634 if (client->ssl != NULL) {
1635 struct SslConn *ssl = client->ssl;
1637 if (ssl->ssl != NULL) {
1638 SSL_shutdown(ssl->ssl);
1643 if (ssl->ctx != NULL) {
1644 SSL_CTX_free(ssl->ctx);
1651 if (client->ssl == NULL && MAX_SHUTDOWN_WAIT >= 0
1652 && shutdown(client->socket, SHUT_WR) == 0) {
1654 while (
qio_read(client->socket, buf,
sizeof(buf), MAX_SHUTDOWN_WAIT) > 0);
1658 close(client->socket);
1659 client->socket = -1;
1660 client->connclose =
false;
1678static void _free(qhttpclient_t *client) {
1679 if (client->socket >= 0) {
1680 client->close(client);
1683 if (client->ssl != NULL)
1685 if (client->hostname != NULL)
1686 free(client->hostname);
1687 if (client->useragent != NULL)
1688 free(client->useragent);
1693#ifndef _DOXYGEN_SKIP
1694static bool _set_socket_option(
int socket) {
1698 if (SET_TCP_LINGER_TIMEOUT > 0) {
1701 li.l_linger = SET_TCP_LINGER_TIMEOUT;
1702 if (setsockopt(socket, SOL_SOCKET, SO_LINGER, &li,
1703 sizeof(
struct linger)) < 0) {
1709 if (SET_TCP_NODELAY > 0) {
1710 int so_tcpnodelay = 1;
1711 if (setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &so_tcpnodelay,
1712 sizeof(so_tcpnodelay)) < 0) {
1720static bool _parse_uri(
const char *uri,
bool *protocol,
char *hostname,
1721 size_t namesize,
int *port) {
1723 if (!strncasecmp(uri,
"http://", CONST_STRLEN(
"http://"))) {
1726 }
else if (!strncasecmp(uri,
"https://", CONST_STRLEN(
"https://"))) {
1733 char *t1 = strstr(uri,
"://");
1735 char *t2 = strstr(t1,
"/");
1737 t2 = (
char *) uri + strlen(uri);
1739 if (t2 - t1 + 1 > namesize)
1741 qstrncpy(hostname, namesize, t1, t2 - t1);
1743 t1 = strstr(hostname,
":");
1746 *port = atoi(t1 + 1);
qgrow_t * qgrow(int options)
Initialize grow.
static void settimeout(qhttpclient_t *client, int timeoutms)
qhttpclient->settimeout(): Sets connection wait timeout.
static bool sendrequest(qhttpclient_t *client, const char *method, const char *uri, qlisttbl_t *reqheaders)
qhttpclient->sendrequest(): Sends a HTTP request to the remote host.
static void * cmd(qhttpclient_t *client, const char *method, const char *uri, void *data, size_t size, int *rescode, size_t *contentslength, qlisttbl_t *reqheaders, qlisttbl_t *resheaders)
qhttpclient->cmd(): Sends a custom request(method) to the remote host and reads it's response.
static off_t recvfile(qhttpclient_t *client, int fd, off_t nbytes)
qhttpclient->recvfile(): Reads data from a HTTP/HTTPS stream and save into a file descriptor.
static bool setssl(qhttpclient_t *client)
qhttpclient->setssl(): Sets connection to HTTPS connection
static ssize_t read_(qhttpclient_t *client, void *buf, size_t nbytes)
qhttpclient->read(): Reads data from a HTTP/HTTPS stream.
static bool _close(qhttpclient_t *client)
qhttpclient->close(): Closes the connection.
static ssize_t write_(qhttpclient_t *client, const void *buf, size_t nbytes)
qhttpclient->write(): Writes data to a HTTP/HTTPS stream.
static void _free(qhttpclient_t *client)
qhttpclient->free(): Free object.
static void setkeepalive(qhttpclient_t *client, bool keepalive)
qhttpclient->setkeepalive(): Sets KEEP-ALIVE feature on/off.
static int readresponse(qhttpclient_t *client, qlisttbl_t *resheaders, off_t *contentlength)
qhttpclient->readresponse(): Reads HTTP response header from the remote host.
qhttpclient_t * qhttpclient(const char *destname, int port)
Initialize & create new HTTP client.
static bool open_(qhttpclient_t *client)
qhttpclient->open(): Opens a connection to the remote host.
static bool head(qhttpclient_t *client, const char *uri, int *rescode, qlisttbl_t *reqheaders, qlisttbl_t *resheaders)
qhttpclient->head(): Sends a HEAD request.
static off_t sendfile_(qhttpclient_t *client, int fd, off_t nbytes)
qhttpclient->sendfile(): Send file data to a HTTP/HTTPS stream.
static ssize_t gets_(qhttpclient_t *client, char *buf, size_t bufsize)
qhttpclient->gets(): Reads a text line from a HTTP/HTTPS stream.
static bool put(qhttpclient_t *client, const char *uri, int fd, off_t length, int *rescode, qlisttbl_t *reqheaders, qlisttbl_t *resheaders, bool(*callback)(void *userdata, off_t sentbytes), void *userdata)
qhttpclient->put(): Uploads a file to the remote host using PUT method.
static bool get(qhttpclient_t *client, const char *uri, int fd, off_t *savesize, int *rescode, qlisttbl_t *reqheaders, qlisttbl_t *resheaders, bool(*callback)(void *userdata, off_t recvbytes), void *userdata)
qhttpclient->get(): Downloads a file from the remote host using GET method.
static void setuseragent(qhttpclient_t *client, const char *useragent)
qhttpclient->setuseragent(): Sets user-agent string.
ssize_t qio_write(int fd, const void *buf, size_t nbytes, int timeoutms)
Write to a file descriptor.
int qio_wait_readable(int fd, int timeoutms)
Test & wait until the file descriptor has readable data.
ssize_t qio_read(int fd, void *buf, size_t nbytes, int timeoutms)
Read from a file descriptor.
ssize_t qio_gets(int fd, char *buf, size_t bufsize, int timeoutms)
Read a line from a file descriptor into the buffer pointed to until either a terminating newline or E...
int qio_wait_writable(int fd, int timeoutms)
Test & wait until the file descriptor is ready for writing.
qlisttbl_t * qlisttbl(int options)
Create a new Q_LIST linked-list container.
bool qsocket_get_addr(struct sockaddr_in *addr, const char *hostname, int port)
Convert hostname to sockaddr_in structure.
char * qstrcpy(char *dst, size_t size, const char *src)
Copy src string to dst.
char * qstrncpy(char *dst, size_t size, const char *src, size_t nbytes)
Copy src string to dst no more than n bytes.
char * qstrtrim(char *str)
Remove white spaces(including CR, LF) from head and tail of the string.