Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset f9a2831 in mainline


Ignore:
Timestamp:
2013-09-17T20:35:01Z (8 years ago)
Author:
Martin Sucha <sucha14@…>
Branches:
lfn, master
Children:
ff364f1
Parents:
b9f7848b
Message:

Split the HTTP library into several files

Location:
uspace/lib/http
Files:
3 added
3 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/http/Makefile

    rb9f7848b rf9a2831  
    3434
    3535SOURCES = \
    36         http.c
     36        http.c \
     37        headers.c \
     38        request.c \
     39        response.c
    3740
    3841include $(USPACE_PREFIX)/Makefile.common
  • uspace/lib/http/http.c

    rb9f7848b rf9a2831  
    4444#include "http.h"
    4545
    46 #define HTTP_METHOD_LINE "%s %s HTTP/1.1\r\n"
    47 #define HTTP_HEADER_LINE "%s: %s\r\n"
    48 #define HTTP_REQUEST_LINE "\r\n"
    49 
    50 static char *cut_str(const char *start, const char *end)
    51 {
    52         size_t size = end - start;
    53         return str_ndup(start, size);
    54 }
    55 
    56 static void recv_reset(http_t *http)
     46void recv_reset(http_t *http)
    5747{
    5848        http->recv_buffer_in = 0;
     
    6151
    6252/** Receive one character (with buffering) */
    63 static int recv_char(http_t *http, char *c, bool consume)
     53int recv_char(http_t *http, char *c, bool consume)
    6454{
    6555        if (http->recv_buffer_out == http->recv_buffer_in) {
     
    7969}
    8070
    81 static ssize_t recv_buffer(http_t *http, char *buf, size_t buf_size)
     71ssize_t recv_buffer(http_t *http, char *buf, size_t buf_size)
    8272{
    8373        /* Flush any buffered data*/
     
    9383
    9484/** Receive a character and if it is c, discard it from input buffer */
    95 static int recv_discard(http_t *http, char discard)
     85int recv_discard(http_t *http, char discard)
    9686{
    9787        char c = 0;
     
    10595
    10696/* Receive a single line */
    107 static ssize_t recv_line(http_t *http, char *line, size_t size)
     97ssize_t recv_line(http_t *http, char *line, size_t size)
    10898{
    10999        size_t written = 0;
     
    198188}
    199189
    200 http_header_t *http_header_create(const char *name, const char *value)
    201 {
    202         char *dname = str_dup(name);
    203         if (dname == NULL)
    204                 return NULL;
    205        
    206         char *dvalue = str_dup(value);
    207         if (dvalue == NULL) {
    208                 free(dname);
    209                 return NULL;
    210         }
    211 
    212         return http_header_create_no_copy(dname, dvalue);
    213 }
    214 
    215 http_header_t *http_header_create_no_copy(char *name, char *value)
    216 {
    217         http_header_t *header = malloc(sizeof(http_header_t));
    218         if (header == NULL)
    219                 return NULL;
    220        
    221         link_initialize(&header->link);
    222         header->name = name;
    223         header->value = value;
    224        
    225         return header;
    226 }
    227 
    228 void http_header_destroy(http_header_t *header)
    229 {
    230         free(header->name);
    231         free(header->value);
    232         free(header);
    233 }
    234 
    235 http_request_t *http_request_create(const char *method, const char *path)
    236 {
    237         http_request_t *req = malloc(sizeof(http_request_t));
    238         if (req == NULL)
    239                 return NULL;
    240        
    241         req->method = str_dup(method);
    242         if (req->method == NULL) {
    243                 free(req);
    244                 return NULL;
    245         }
    246        
    247         req->path = str_dup(path);
    248         if (req->path == NULL) {
    249                 free(req->method);
    250                 free(req);
    251                 return NULL;
    252         }
    253        
    254         list_initialize(&req->headers);
    255        
    256         return req;
    257 }
    258 
    259 void http_request_destroy(http_request_t *req)
    260 {
    261         free(req->method);
    262         free(req->path);
    263         link_t *link = req->headers.head.next;
    264         while (link != &req->headers.head) {
    265                 link_t *next = link->next;
    266                 http_header_t *header = list_get_instance(link, http_header_t, link);
    267                 http_header_destroy(header);
    268                 link = next;
    269         }
    270         free(req);
    271 }
    272 
    273 static ssize_t http_encode_method(char *buf, size_t buf_size,
    274     const char *method, const char *path)
    275 {
    276         if (buf == NULL) {
    277                 return printf_size(HTTP_METHOD_LINE, method, path);
    278         }
    279         else {
    280                 return snprintf(buf, buf_size, HTTP_METHOD_LINE, method, path);
    281         }
    282 }
    283 
    284 static ssize_t http_encode_header(char *buf, size_t buf_size,
    285     http_header_t *header)
    286 {
    287         /* TODO properly split long header values */
    288         if (buf == NULL) {
    289                 return printf_size(HTTP_HEADER_LINE, header->name, header->value);
    290         }
    291         else {
    292                 return snprintf(buf, buf_size,
    293                     HTTP_HEADER_LINE, header->name, header->value);
    294         }
    295 }
    296 
    297 int http_request_format(http_request_t *req, char **out_buf,
    298     size_t *out_buf_size)
    299 {
    300         /* Compute the size of the request */
    301         ssize_t meth_size = http_encode_method(NULL, 0, req->method, req->path);
    302         if (meth_size < 0)
    303                 return meth_size;
    304         size_t size = meth_size;
    305        
    306         list_foreach(req->headers, link, http_header_t, header) {
    307                 ssize_t header_size = http_encode_header(NULL, 0, header);
    308                 if (header_size < 0)
    309                         return header_size;
    310                 size += header_size;
    311         }
    312         size += str_length(HTTP_REQUEST_LINE);
    313        
    314         char *buf = malloc(size);
    315         if (buf == NULL)
    316                 return ENOMEM;
    317        
    318         char *pos = buf;
    319         size_t pos_size = size;
    320         ssize_t written = http_encode_method(pos, pos_size, req->method, req->path);
    321         if (written < 0) {
    322                 free(buf);
    323                 return written;
    324         }
    325         pos += written;
    326         pos_size -= written;
    327        
    328         list_foreach(req->headers, link, http_header_t, header) {
    329                 written = http_encode_header(pos, pos_size, header);
    330                 if (written < 0) {
    331                         free(buf);
    332                         return written;
    333                 }
    334                 pos += written;
    335                 pos_size -= written;
    336         }
    337        
    338         size_t rlsize = str_size(HTTP_REQUEST_LINE);
    339         memcpy(pos, HTTP_REQUEST_LINE, rlsize);
    340         pos_size -= rlsize;
    341         assert(pos_size == 0);
    342        
    343         *out_buf = buf;
    344         *out_buf_size = size;
    345         return EOK;
    346 }
    347 
    348 int http_send_request(http_t *http, http_request_t *req)
    349 {
    350         char *buf;
    351         size_t buf_size;
    352        
    353         int rc = http_request_format(req, &buf, &buf_size);
    354         if (rc != EOK)
    355                 return rc;
    356        
    357         rc = send(http->conn_sd, buf, buf_size, 0);
    358         free(buf);
    359        
    360         return rc;
    361 }
    362 
    363 int http_parse_status(const char *line, http_version_t *out_version,
    364     uint16_t *out_status, char **out_message)
    365 {
    366         http_version_t version;
    367         uint16_t status;
    368         char *message = NULL;
    369        
    370         if (!str_test_prefix(line, "HTTP/"))
    371                 return EINVAL;
    372        
    373         const char *pos_version = line + 5;
    374         const char *pos = pos_version;
    375        
    376         int rc = str_uint8_t(pos_version, &pos, 10, false, &version.major);
    377         if (rc != EOK)
    378                 return rc;
    379         if (*pos != '.')
    380                 return EINVAL;
    381         pos++;
    382        
    383         pos_version = pos;
    384         rc = str_uint8_t(pos_version, &pos, 10, false, &version.minor);
    385         if (rc != EOK)
    386                 return rc;
    387         if (*pos != ' ')
    388                 return EINVAL;
    389         pos++;
    390        
    391         const char *pos_status = pos;
    392         rc = str_uint16_t(pos_status, &pos, 10, false, &status);
    393         if (rc != EOK)
    394                 return rc;
    395         if (*pos != ' ')
    396                 return EINVAL;
    397         pos++;
    398        
    399         if (out_message) {
    400                 message = str_dup(pos);
    401                 if (message == NULL)
    402                         return ENOMEM;
    403         }
    404        
    405         if (out_version)
    406                 *out_version = version;
    407         if (out_status)
    408                 *out_status = status;
    409         if (out_message)
    410                 *out_message = message;
    411         return EOK;
    412 }
    413 
    414 int http_parse_header(const char *line, char **out_name, char **out_value)
    415 {
    416         const char *pos = line;
    417         while (*pos != 0 && *pos != ':') pos++;
    418         if (*pos != ':')
    419                 return EINVAL;
    420        
    421         char *name = cut_str(line, pos);
    422         if (name == NULL)
    423                 return ENOMEM;
    424        
    425         pos++;
    426        
    427         while (*pos == ' ') pos++;
    428        
    429         char *value = str_dup(pos);
    430         if (value == NULL) {
    431                 free(name);
    432                 return ENOMEM;
    433         }
    434        
    435         *out_name = name;
    436         *out_value = value;
    437        
    438         return EOK;
    439 }
    440 
    441 int http_receive_response(http_t *http, http_response_t **out_response)
    442 {
    443         http_response_t *resp = malloc(sizeof(http_response_t));
    444         if (resp == NULL)
    445                 return ENOMEM;
    446         memset(resp, 0, sizeof(http_response_t));
    447         list_initialize(&resp->headers);
    448        
    449         char *line = malloc(http->buffer_size);
    450         if (line == NULL) {
    451                 free(resp);
    452                 return ENOMEM;
    453         }
    454        
    455         int rc = recv_line(http, line, http->buffer_size);
    456         if (rc < 0)
    457                 goto error;
    458        
    459         rc = http_parse_status(line, &resp->version, &resp->status,
    460             &resp->message);
    461         if (rc != EOK)
    462                 goto error;
    463        
    464         while (true) {
    465                 rc = recv_line(http, line, http->buffer_size);
    466                 if (rc < 0)
    467                         goto error;
    468                 if (*line == 0)
    469                         break;
    470                
    471                 char *name = NULL;
    472                 char *value = NULL;
    473                 rc = http_parse_header(line, &name, &value);
    474                 if (rc != EOK)
    475                         goto error;
    476                
    477                 http_header_t *header = http_header_create_no_copy(name, value);
    478                 if (header == NULL) {
    479                         free(name);
    480                         free(value);
    481                         rc = ENOMEM;
    482                         goto error;
    483                 }
    484                
    485                 list_append(&header->link, &resp->headers);
    486         }
    487        
    488         *out_response = resp;
    489        
    490         return EOK;
    491 error:
    492         free(line);
    493         http_response_destroy(resp);
    494         return rc;
    495 }
    496 
    497 int http_receive_body(http_t *http, void *buf, size_t buf_size)
    498 {
    499         return recv_buffer(http, buf, buf_size);
    500 }
    501 
    502 void http_response_destroy(http_response_t *resp)
    503 {
    504         free(resp->message);
    505         link_t *link = resp->headers.head.next;
    506         while (link != &resp->headers.head) {
    507                 link_t *next = link->next;
    508                 http_header_t *header = list_get_instance(link, http_header_t, link);
    509                 http_header_destroy(header);
    510                 link = next;
    511         }
    512         free(resp);
    513 }
    514 
    515190int http_close(http_t *http)
    516191{
  • uspace/lib/http/http.h

    rb9f7848b rf9a2831  
    9191    char **);
    9292extern int http_parse_header(const char *, char **, char **);
     93ssize_t http_encode_header(char *, size_t, http_header_t *);
    9394extern int http_receive_response(http_t *, http_response_t **);
    9495extern int http_receive_body(http_t *, void *, size_t);
     
    9798extern void http_destroy(http_t *);
    9899
     100extern void recv_reset(http_t *);
     101extern int recv_char(http_t *, char *, bool);
     102extern ssize_t recv_buffer(http_t *, char *, size_t);
     103extern int recv_discard(http_t *, char);
     104extern ssize_t recv_line(http_t *, char *, size_t);
     105
    99106#endif
    100107
Note: See TracChangeset for help on using the changeset viewer.