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;
}
|