Changeset 3ce68b7 in mainline


Ignore:
Timestamp:
2013-09-26T09:01:36Z (11 years ago)
Author:
Martin Sucha <sucha14@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
b623b68
Parents:
c17469e
Message:

libhttp: receive headers correctly

Location:
uspace/lib/http
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/http/headers.c

    rc17469e r3ce68b7  
    4040
    4141#include "http.h"
     42#include "http-ctype.h"
    4243
    4344#define HTTP_HEADER_LINE "%s: %s\r\n"
    44 
    45 static char *cut_str(const char *start, const char *end)
    46 {
    47         size_t size = end - start;
    48         return str_ndup(start, size);
    49 }
    5045
    5146void http_header_init(http_header_t *header)
     
    9893}
    9994
    100 int http_header_parse(const char *line, http_header_t *header)
    101 {
    102         const char *pos = line;
    103         while (*pos != 0 && *pos != ':') pos++;
    104         if (*pos != ':')
     95int http_header_receive_name(receive_buffer_t *rb, char **out_name)
     96{
     97        receive_buffer_mark_t name_start;
     98        receive_buffer_mark_t name_end;
     99       
     100        recv_mark(rb, &name_start);
     101        recv_mark(rb, &name_end);
     102       
     103        char c = 0;
     104        do {
     105                recv_mark_update(rb, &name_end);
     106               
     107                int rc = recv_char(rb, &c, true);
     108                if (rc != EOK) {
     109                        recv_unmark(rb, &name_start);
     110                        recv_unmark(rb, &name_end);
     111                        return rc;
     112                }
     113        } while (is_token(c));
     114       
     115        if (c != ':') {
     116                recv_unmark(rb, &name_start);
     117                recv_unmark(rb, &name_end);
    105118                return EINVAL;
    106        
    107         char *name = cut_str(line, pos);
    108         if (name == NULL)
    109                 return ENOMEM;
    110        
    111         pos++;
    112        
    113         while (*pos == ' ') pos++;
    114        
    115         char *value = str_dup(pos);
    116         if (value == NULL) {
     119        }
     120       
     121        char *name = NULL;
     122        int rc = recv_cut_str(rb, &name_start, &name_end, &name);
     123        recv_unmark(rb, &name_start);
     124        recv_unmark(rb, &name_end);
     125        if (rc != EOK)
     126                return rc;
     127       
     128        *out_name = name;
     129        return EOK;
     130}
     131
     132int http_header_receive_value(receive_buffer_t *rb, char **out_value)
     133{
     134        int rc = EOK;
     135        char c = 0;
     136       
     137        receive_buffer_mark_t value_start;
     138        recv_mark(rb, &value_start);
     139       
     140        /* Ignore any inline LWS */
     141        while (true) {
     142                recv_mark_update(rb, &value_start);
     143                rc = recv_char(rb, &c, false);
     144                if (rc != EOK)
     145                        goto error;
     146               
     147                if (c != ' ' && c != '\t')
     148                        break;
     149               
     150                rc = recv_char(rb, &c, true);
     151                if (rc != EOK)
     152                        goto error;
     153        }
     154       
     155        receive_buffer_mark_t value_end;
     156        recv_mark(rb, &value_end);
     157       
     158        while (true) {
     159                recv_mark_update(rb, &value_end);
     160               
     161                rc = recv_char(rb, &c, true);
     162                if (rc != EOK)
     163                        goto error_end;
     164               
     165                if (c != '\r' && c != '\n')
     166                        continue;
     167               
     168                rc = recv_discard(rb, (c == '\r' ? '\n' : '\r'));
     169                if (rc < 0)
     170                        goto error_end;
     171               
     172                rc = recv_char(rb, &c, false);
     173                if (rc != EOK)
     174                        goto error_end;
     175               
     176                if (c != ' ' && c != '\t')
     177                        break;
     178               
     179                /* Ignore the char */
     180                rc = recv_char(rb, &c, true);
     181                if (rc != EOK)
     182                        goto error_end;
     183        }
     184       
     185        char *value = NULL;
     186        rc = recv_cut_str(rb, &value_start, &value_end, &value);
     187        recv_unmark(rb, &value_start);
     188        recv_unmark(rb, &value_end);
     189        if (rc != EOK)
     190                return rc;
     191       
     192        *out_value = value;
     193        return EOK;
     194error_end:
     195        recv_unmark(rb, &value_end);
     196error:
     197        recv_unmark(rb, &value_start);
     198        return rc;
     199}
     200
     201int http_header_receive(receive_buffer_t *rb, http_header_t *header)
     202{
     203        char *name = NULL;
     204        int rc = http_header_receive_name(rb, &name);
     205        if (rc != EOK) {
     206                printf("Failed receiving header name\n");
     207                return rc;
     208        }
     209       
     210        char *value = NULL;
     211        rc = http_header_receive_value(rb, &value);
     212        if (rc != EOK) {
    117213                free(name);
    118                 return ENOMEM;
     214                return rc;
    119215        }
    120216       
    121217        header->name = name;
    122218        header->value = value;
    123        
    124219        return EOK;
    125220}
    126221
     222/** Normalize HTTP header value
     223 *
     224 * @see RFC2616 section 4.2
     225 */
     226void http_header_normalize_value(char *value)
     227{
     228        size_t read_index = 0;
     229        size_t write_index = 0;
     230       
     231        while (is_lws(value[read_index])) read_index++;
     232       
     233        while (value[read_index] != 0) {
     234                if (is_lws(value[read_index])) {
     235                        while (is_lws(value[read_index])) read_index++;
     236                       
     237                        if (value[read_index] != 0)
     238                                value[write_index++] = ' ';
     239                       
     240                        continue;
     241                }
     242               
     243                value[write_index++] = value[read_index++];
     244        }
     245       
     246        value[write_index] = 0;
     247}
     248
    127249/** @}
    128250 */
  • uspace/lib/http/http.h

    rc17469e r3ce68b7  
    8484extern void http_header_init(http_header_t *);
    8585extern http_header_t *http_header_create(const char *, const char *);
    86 extern int http_header_parse(const char *, http_header_t *);
     86extern int http_header_receive_name(receive_buffer_t *, char **);
     87extern int http_header_receive_value(receive_buffer_t *, char **);
     88extern int http_header_receive(receive_buffer_t *, http_header_t *);
     89extern void http_header_normalize_value(char *);
    8790ssize_t http_header_encode(http_header_t *, char *, size_t);
    8891extern void http_header_destroy(http_header_t *);
  • uspace/lib/http/receive-buffer.c

    rc17469e r3ce68b7  
    3939#include <errno.h>
    4040#include <macros.h>
     41#include <adt/list.h>
    4142
    4243#include "receive-buffer.h"
     
    5152        rb->out = 0;
    5253        rb->size = buffer_size;
     54       
     55        list_initialize(&rb->marks);
     56       
    5357        rb->buffer = malloc(buffer_size);
    5458        if (rb->buffer == NULL)
     
    5761}
    5862
     63static ssize_t dummy_receive(void *unused, void *buf, size_t buf_size)
     64{
     65        return 0;
     66}
     67
     68int recv_buffer_init_const(receive_buffer_t *rb, void *buf, size_t size)
     69{
     70        int rc = recv_buffer_init(rb, size, dummy_receive, NULL);
     71        if (rc != EOK)
     72                return rc;
     73       
     74        memcpy(rb->buffer, buf, size);
     75        rb->in = size;
     76        return EOK;
     77}
     78
    5979void recv_buffer_fini(receive_buffer_t *rb)
    6080{
     
    6888}
    6989
     90void recv_mark(receive_buffer_t *rb, receive_buffer_mark_t *mark)
     91{
     92        link_initialize(&mark->link);
     93        list_append(&mark->link, &rb->marks);
     94        recv_mark_update(rb, mark);
     95}
     96
     97void recv_unmark(receive_buffer_t *rb, receive_buffer_mark_t *mark)
     98{
     99        list_remove(&mark->link);
     100}
     101
     102void recv_mark_update(receive_buffer_t *rb, receive_buffer_mark_t *mark)
     103{
     104        mark->offset = rb->out;
     105}
     106
     107int recv_cut(receive_buffer_t *rb, receive_buffer_mark_t *a, receive_buffer_mark_t *b, void **out_buf, size_t *out_size)
     108{
     109        if (a->offset > b->offset)
     110                return EINVAL;
     111       
     112        size_t size = b->offset - a->offset;
     113        void *buf = malloc(size);
     114        if (buf == NULL)
     115                return ENOMEM;
     116       
     117        memcpy(buf, rb->buffer + a->offset, size);
     118        *out_buf = buf;
     119        *out_size = size;
     120        return EOK;
     121}
     122
     123int recv_cut_str(receive_buffer_t *rb, receive_buffer_mark_t *a, receive_buffer_mark_t *b, char **out_buf)
     124{
     125        if (a->offset > b->offset)
     126                return EINVAL;
     127       
     128        size_t size = b->offset - a->offset;
     129        char *buf = malloc(size + 1);
     130        if (buf == NULL)
     131                return ENOMEM;
     132       
     133        memcpy(buf, rb->buffer + a->offset, size);
     134        buf[size] = 0;
     135        for (size_t i = 0; i < size; i++) {
     136                if (buf[i] == 0) {
     137                        free(buf);
     138                        return EIO;
     139                }
     140        }
     141        *out_buf = buf;
     142        return EOK;
     143}
     144
     145
    70146/** Receive one character (with buffering) */
    71147int recv_char(receive_buffer_t *rb, char *c, bool consume)
    72148{
    73149        if (rb->out == rb->in) {
    74                 recv_reset(rb);
     150                size_t free = rb->size - rb->in;
     151                if (free == 0) {
     152                        size_t min_mark = rb->size;
     153                        list_foreach(rb->marks, link, receive_buffer_mark_t, mark) {
     154                                min_mark = min(min_mark, mark->offset);
     155                        }
     156                       
     157                        if (min_mark == 0)
     158                                return ELIMIT;
     159                       
     160                        size_t new_in = rb->in - min_mark;
     161                        memmove(rb->buffer, rb->buffer + min_mark, new_in);
     162                        rb->out = rb->in = new_in;
     163                        free = rb->size - rb->in;
     164                        list_foreach(rb->marks, link, receive_buffer_mark_t, mark) {
     165                                mark->offset -= min_mark;
     166                        }
     167                }
    75168               
    76                 ssize_t rc = rb->receive(rb->client_data, rb->buffer, rb->size);
     169                ssize_t rc = rb->receive(rb->client_data, rb->buffer + rb->in, free);
    77170                if (rc <= 0)
    78171                        return rc;
     
    100193}
    101194
    102 /** Receive a character and if it is c, discard it from input buffer */
    103 int recv_discard(receive_buffer_t *rb, char discard)
     195/** Receive a character and if it is c, discard it from input buffer
     196 * @return number of characters discarded (0 or 1) or negative error code
     197 */
     198ssize_t recv_discard(receive_buffer_t *rb, char discard)
    104199{
    105200        char c = 0;
     
    108203                return rc;
    109204        if (c != discard)
    110                 return EOK;
    111         return recv_char(rb, &c, true);
     205                return 0;
     206        rc = recv_char(rb, &c, true);
     207        if (rc != EOK)
     208                return rc;
     209        return 1;
     210}
     211
     212/** Receive an end of line, either CR, LF, CRLF or LFCR
     213 *
     214 * @return number of bytes read (0 if no newline is present in the stream)
     215 *         or negative error code
     216 */
     217ssize_t recv_eol(receive_buffer_t *rb)
     218{
     219        char c = 0;
     220        int rc = recv_char(rb, &c, false);
     221        if (rc != EOK)
     222                return rc;
     223       
     224        if (c != '\r' && c != '\n')
     225                return 0;
     226       
     227        rc = recv_char(rb, &c, true);
     228        if (rc != EOK)
     229                return rc;
     230       
     231        ssize_t rc2 = recv_discard(rb, (c == '\r' ? '\n' : '\r'));
     232        if (rc2 < 0)
     233                return rc2;
     234       
     235        return 1 + rc2;
    112236}
    113237
  • uspace/lib/http/receive-buffer.h

    rc17469e r3ce68b7  
    3737#define HTTP_RECEIVE_BUFFER_H_
    3838
     39#include <adt/list.h>
    3940
    4041/** Receive data.
     
    5556        void *client_data;
    5657        receive_func_t receive;
     58       
     59        list_t marks;
    5760} receive_buffer_t;
    5861
     62typedef struct {
     63        link_t link;
     64        size_t offset;
     65} receive_buffer_mark_t;
     66
    5967extern int recv_buffer_init(receive_buffer_t *, size_t, receive_func_t, void *);
     68extern int recv_buffer_init_const(receive_buffer_t *, void *, size_t);
    6069extern void recv_buffer_fini(receive_buffer_t *);
    6170extern void recv_reset(receive_buffer_t *);
     71extern void recv_mark(receive_buffer_t *, receive_buffer_mark_t *);
     72extern void recv_unmark(receive_buffer_t *, receive_buffer_mark_t *);
     73extern void recv_mark_update(receive_buffer_t *, receive_buffer_mark_t *);
     74extern int recv_cut(receive_buffer_t *, receive_buffer_mark_t *,
     75    receive_buffer_mark_t *, void **, size_t *);
     76extern int recv_cut_str(receive_buffer_t *, receive_buffer_mark_t *,
     77    receive_buffer_mark_t *, char **);
    6278extern int recv_char(receive_buffer_t *, char *, bool);
    6379extern ssize_t recv_buffer(receive_buffer_t *, char *, size_t);
    64 extern int recv_discard(receive_buffer_t *, char);
     80extern ssize_t recv_discard(receive_buffer_t *, char);
     81extern ssize_t recv_eol(receive_buffer_t *);
    6582extern ssize_t recv_line(receive_buffer_t *, char *, size_t);
    6683
  • uspace/lib/http/response.c

    rc17469e r3ce68b7  
    116116       
    117117        while (true) {
    118                 rc = recv_line(&http->recv_buffer, line, http->buffer_size);
     118                rc = recv_eol(&http->recv_buffer);
    119119                if (rc < 0)
    120120                        goto error;
    121                 if (*line == 0)
     121               
     122                /* Empty line ends header part */
     123                if (rc > 0)
    122124                        break;
    123125               
     
    129131                http_header_init(header);
    130132               
    131                 rc = http_header_parse(line, header);
    132                 if (rc != EOK)
     133                rc = http_header_receive(&http->recv_buffer, header);
     134                if (rc != EOK) {
     135                        free(header);
    133136                        goto error;
     137                }
    134138               
    135139                list_append(&header->link, &resp->headers);
Note: See TracChangeset for help on using the changeset viewer.