20 #include "fileutils.h"
43 const char* authority;
59 #define MAIN_ERR_PREFIX "HTTP: "
62 #define HTTP_PERM (api_posix_mode_t) (API_POSIX_S_IRUSR | API_POSIX_S_IWUSR)
65 #define HTTP_LINE_MAX (size_t) 8192
71 static int http_prepare_local_file(
int* fd,
const char* lpn)
76 API_POSIX_O_RDWR | API_POSIX_O_CREAT| API_POSIX_O_TRUNC,
81 if(res) {
PRINT_ERROR(
"Unable to create and lock target file"); }
97 static void http_uri_data_destructor(
struct http_uri_data** uri_data)
101 api_posix_free((
void*) (*uri_data)->authority);
102 api_posix_free((
void*) (*uri_data)->path);
103 api_posix_free((
void*) *uri_data);
126 static int http_uri_data_constructor(
struct http_uri_data** uri_data,
135 *uri_data = (
struct http_uri_data*)
136 api_posix_malloc(
sizeof(
struct http_uri_data));
137 if(NULL != *uri_data)
139 (*uri_data)->authority = NULL;
140 (*uri_data)->path = NULL;
142 if(strncmp(uri,
"http://", 7)) { res = -2; }
147 q = strchr(p, (
int)
'/');
150 len = (size_t) (q - p);
151 t = (
char*) api_posix_malloc(len + (
size_t) 1);
156 (*uri_data)->authority = t;
159 t = (
char*) api_posix_malloc(len + (
size_t) 1);
164 (*uri_data)->path = t;
176 http_uri_data_destructor(uri_data);
198 static int http_connect(
int* sd,
const char* authority)
201 int af = API_POSIX_AF_UNSPEC;
202 const char* host = authority;
203 const char* service =
"www";
208 int connection_failed = 0;
214 p = strchr(authority, (
int)
':');
217 i = (size_t) (p - authority);
218 len = strlen(authority);
219 q = (
char*) api_posix_malloc(len + (
size_t) 1);
220 if(NULL == q) { res = -1; }
223 memcpy(q, authority, len);
236 printf(
"----------------------\n");
237 printf(
"Host : %s\n", host);
238 printf(
"Service: %s\n", service);
239 printf(
"----------------------\n");
253 if(connection_failed) { res = -3; }
257 if(NULL != q) { api_posix_free((
void*) q); }
275 static int http_te_check(
char* resp_header)
278 api_posix_locale_t lcp = 0;
279 const char* te_hfn =
"Transfer-Encoding:";
280 size_t te_hfn_len = strlen(te_hfn);
281 const char* te_chunked =
"chunked";
282 size_t te_chunked_len = strlen(te_chunked);
283 char* rh = resp_header;
288 lcp = api_posix_newlocale(API_POSIX_LC_CTYPE_MASK,
"POSIX",
289 (api_posix_locale_t) 0);
290 if((api_posix_locale_t) 0 == lcp)
301 p = strchr(rh, 0x0A);
305 if(!api_posix_strncasecmp_l(rh, te_hfn, te_hfn_len, lcp))
309 while(0x09 == (
int) rh[i] || 0x20 == (
int) rh[i]) { ++i; }
310 if(!api_posix_strncasecmp_l(&rh[i], te_chunked, te_chunked_len,
317 printf(
"%s: %sResponse has chunked transfer encoding\n",
333 if((api_posix_locale_t) 0 != lcp) { api_posix_freelocale(lcp); }
351 static int http_add_to_buffer(
char** buf,
size_t* l,
const char* line)
357 *buf = api_posix_realloc(*buf, *l + len);
360 PRINT_ERROR(
"Out of memory while adding data to buffer");
364 strcpy(&(*buf)[*l - (
size_t) 1], line);
384 static int http_get_tx(
int sd,
struct http_uri_data* uri_data)
396 rv = api_posix_snprintf(line,
HTTP_LINE_MAX,
"GET %s HTTP/1.1\r\n",
400 res = http_add_to_buffer(&buf, &l, line);
406 uri_data->authority);
409 res = http_add_to_buffer(&buf, &l, line);
415 rv = api_posix_snprintf(line,
HTTP_LINE_MAX,
"Connection: close\r\n");
418 res = http_add_to_buffer(&buf, &l, line);
426 "Cache-Control: max-age=1800\r\n");
429 res = http_add_to_buffer(&buf, &l, line);
444 "Accept: application/pkix-crl, "
445 "application/pkcs7-crl;q=0.8, "
446 "application/x-pkcs7-crl;q=0.2\r\n");
449 res = http_add_to_buffer(&buf, &l, line);
457 "Accept-Encoding: identity\r\n");
460 res = http_add_to_buffer(&buf, &l, line);
466 rv = api_posix_snprintf(line,
HTTP_LINE_MAX,
"User-Agent: %s/%s\r\n",
467 CFG_NAME, CFG_VERSION);
470 res = http_add_to_buffer(&buf, &l, line);
479 res = http_add_to_buffer(&buf, &l, line);
484 printf(
"----------------------\n");
485 if(!res) { printf(
"%s", buf); }
486 printf(
"----------------------\n");
492 len = l - (size_t) 1;
496 do { rv2 = api_posix_send(sd, &buf[i], len - i, 0); }
497 while((ssize_t) -1 == rv2 && API_POSIX_EINTR == api_posix_errno);
498 if((ssize_t) -1 == rv2)
509 api_posix_free((
void*) buf);
530 static int http_get_rx_header(
struct http_status* sc,
int sd,
int* cte)
538 api_posix_ssize_t rv;
541 int df[3] = { 100, 10, 1 };
549 resp = (
char*) api_posix_malloc(len);
552 PRINT_ERROR(
"Out of memory while receiving response");
559 while(!res && !eoh && len > ri)
565 rv = api_posix_recv(sd, &resp[ri], len - ri, API_POSIX_MSG_PEEK);
567 while(-1 == rv && API_POSIX_EINTR == api_posix_errno);
583 if(1 == i &&
'\r' == resp[i - 1])
592 if(
'\r' == resp[i - 1]
593 &&
'\n' == resp[i - 2] &&
'\r' == resp[i - 3])
610 do { rv = api_posix_recv(sd, &resp[ri], i - ri, 0); }
611 while(-1 == rv && API_POSIX_EINTR == api_posix_errno);
626 p = (
char*) api_posix_realloc(resp, len);
629 PRINT_ERROR(
"Out of memory while receiving response");
635 if(!res && !eoh) { res = -1; }
643 printf(
"----------------------\n");
644 if(!res) { printf(
"%s", resp); }
645 printf(
"----------------------\n");
649 res = http_te_check(resp);
663 p = strchr(resp, (
int)
' ');
664 if(NULL == p) { res = -1; }
667 if((
size_t) 3 > strlen(++p)) { res = -1; }
671 for(i = 0; i < 3; ++i)
675 sc->digit[i] = p[i] - (char) 48;
676 sc->code += df[i] * (int) (sc->digit[i]);
682 api_posix_free((
void*) resp);
699 static int http_get_chunk_size(
size_t* cs,
int sd)
703 api_posix_ssize_t rv;
705 unsigned long int value;
711 do { rv = api_posix_recv(sd, &line[i], 1, 0); }
712 while(-1 == rv && API_POSIX_EINTR == api_posix_errno);
719 while(0x0A != (
int) line[i++]);
724 res = sscanf(line,
"%lx", &value);
725 if(1 != res) { res = -1; }
728 if((
unsigned long int) API_POSIX_UINT_MAX < value) { res = -1; }
731 *cs = (size_t) value;
738 if(res) {
PRINT_ERROR(
"Reading chunk size failed"); }
758 static int http_get_rx_body(
int fd,
int sd,
int cte)
761 api_posix_ssize_t rv;
763 size_t chunk_size = 4096;
771 chunk = (
char*) api_posix_malloc(chunk_size);
772 if(NULL == chunk) { res = -1; }
776 do { rv = api_posix_recv(sd, chunk, chunk_size, 0); }
777 while(-1 == rv && API_POSIX_EINTR == api_posix_errno);
789 if(0 > res) { res = -1; }
798 if(http_get_chunk_size(&chunk_size, sd)) { res = -1; }
802 p = (
char*) api_posix_realloc(chunk, chunk_size);
803 if(NULL == p) { res = -1; }
809 while(chunk_size > len)
814 rv = api_posix_recv(sd, &chunk[len], chunk_size - len, 0);
816 while(-1 == rv && API_POSIX_EINTR == api_posix_errno);
829 if(0 > res) { res = -1; }
838 do { rv = api_posix_recv(sd, &crlf[len], 2 - len, 0); }
839 while(-1 == rv && API_POSIX_EINTR == api_posix_errno);
848 if(!res && (0x0D != (
int) crlf[0] || 0x0A != crlf[1]))
856 while(!res && chunk_size);
860 api_posix_free((
void*) chunk);
891 struct http_uri_data* uri_data = NULL;
893 struct http_status sc;
904 res = http_prepare_local_file(&fd, lpn);
908 if(!res) { res = http_uri_data_constructor(&uri_data, uri); }
909 if(!res) { res = http_connect(&sd, uri_data->authority); }
912 if(!res) { res = http_get_tx(sd, uri_data); }
913 if(!res) { res = http_get_rx_header(&sc, sd, &cte); }
917 if(2 != (
int) sc.digit[0])
920 if(5 == (
int) sc.digit[0])
924 if(404 == sc.code) { res = -4; }
927 if(!res) { res = http_get_rx_body(fd, sd, cte); }
933 http_uri_data_destructor(&uri_data);
953 printf(
"%s: %sFile successfully downloaded\n", CFG_NAME,
MAIN_ERR_PREFIX);