File: wire.c

package info (click to toggle)
inn2 2.4.5-5
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 8,912 kB
  • ctags: 7,860
  • sloc: ansic: 85,104; perl: 11,427; sh: 9,863; makefile: 2,498; yacc: 1,563; python: 298; lex: 252; tcl: 7
file content (174 lines) | stat: -rw-r--r-- 5,226 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*  $Id: wire.c 7258 2005-06-06 03:14:45Z eagle $
**
**  Wire format article utilities.
**
**  Originally written by Alex Kiernan (alex.kiernan@thus.net)
**
**  These routines manipulate wire format articles; in particular, they should
**  be safe in the presence of embedded NULs.  They assume wire format
**  conventions (\r\n as a line ending, in particular) and will not work with
**  articles in native format.
**
**  The functions in this file take const char * pointers and return char *
**  pointers so that they can work on both const char * and char * article
**  bodies without changing the const sense.  This unfortunately means that
**  the routines in this file will produce warnings about const being cast
**  away.  To avoid those, one would need to duplicate all the code in this
**  file or use C++.
*/

#include "config.h"
#include "clibrary.h"
#include <assert.h>

#include "inn/wire.h"
#include "libinn.h"

/*
**  Given a pointer to the start of an article, locate the first octet of the
**  body (which may be the octet beyond the end of the buffer if your article
**  is bodiless).
*/
char *
wire_findbody(const char *article, size_t length)
{
    char *p;
    const char *end;

    /* Handle the degenerate case of an article with no headers. */
    if (length > 5 && article[0] == '\r' && article[1] == '\n')
        return (char *) article + 2;

    /* Jump from \r to \r and give up if we're too close to the end. */
    end = article + length;
    for (p = (char *) article; (p + 4) <= end; ++p) {
        p = memchr(p, '\r', end - p - 3);
        if (p == NULL)
            break;
        if (memcmp(p, "\r\n\r\n", 4) == 0) {
            p += 4;
            return p;
        }
    }
    return NULL;
}


/*
**  Given a pointer into an article and a pointer to the last octet of the
**  article, find the next line ending and return a pointer to the first
**  character after that line ending.  If no line ending is found in the
**  article or if it is at the end of the article, return NULL.
*/
char *
wire_nextline(const char *article, const char *end)
{
    char *p;

    for (p = (char *) article; (p + 2) <= end; ++p) {
        p = memchr(p, '\r', end - p - 2);
        if (p == NULL)
            break;
        if (p[1] == '\n') {
            p += 2;
            return p;
        }
    }
    return NULL;
}


/*
**  Returns true if line is the beginning of a valid header for header, also
**  taking the length of the header name as a third argument.  Assumes that
**  there is at least length + 2 bytes of data at line, and that the header
**  name doesn't contain nul.
*/
static bool
isheader(const char *line, const char *header, size_t length)
{
    if (line[length] != ':' || !ISWHITE(line[length + 1]))
        return false;
    return strncasecmp(line, header, length) == 0;
}


/*
**  Skip over folding whitespace, as defined by RFC 2822.  Takes a pointer to
**  where to start skipping and a pointer to the end of the data, and will not
**  return a pointer past the end pointer.  If skipping folding whitespace
**  takes us past the end of data, return NULL.
*/
static char *
skip_fws(char *text, const char *end)
{
    char *p;

    for (p = text; p <= end; p++) {
        if (p < end + 1 && p[0] == '\r' && p[1] == '\n' && ISWHITE(p[2]))
            p += 2;
        if (!ISWHITE(*p))
            return p;
    }
    return NULL;
}


/*
**  Given a pointer to the start of the article, the article length, and the
**  header to look for, find the first occurance of that header in the
**  article.  Skip over headers with no content, but allow for headers that
**  are folded before the first text in the header.  If no matching headers
**  with content other than spaces and tabs are found, return NULL.
*/
char *
wire_findheader(const char *article, size_t length, const char *header)
{
    char *p;
    const char *end;
    ptrdiff_t headerlen;

    headerlen = strlen(header);
    end = article + length - 1;

    /* There has to be enough space left in the article for at least the
       header, the colon, whitespace, and one non-whitespace character, hence
       3, minus 1 since the character pointed to by end is part of the
       article. */
    p = (char *) article;
    while (p != NULL && end - p > headerlen + 2) {
        if (p[0] == '\r' && p[1] == '\n')
            return NULL;
        else if (isheader(p, header, headerlen)) {
            p = skip_fws(p + headerlen + 2, end);
            if (p == NULL)
                return NULL;
            if (p >= end || p[0] != '\r' || p[1] != '\n')
                return p;
        }
        p = wire_nextline(p, end);
    }
    return NULL;
}


/*
**  Given a pointer to a header and a pointer to the last octet of the
**  article, find the end of the header (a pointer to the final \n of the
**  header value).  If the header contents don't end in \r\n, return NULL.
*/
char *
wire_endheader(const char *header, const char *end)
{
    char *p;

    p = wire_nextline(header, end);
    while (p != NULL) {
        if (!ISWHITE(*p))
            return p - 1;
        p = wire_nextline(p, end);
    }
    if (end - header >= 1 && *end == '\n' && *(end - 1) == '\r')
        return (char *) end;
    return NULL;
}