no preallocating if there's no state file
[syren.git] / src / syren_hdrs.c
blob6acbbf9d7f0b9bbc5162c1158337f7a5b1d82f3e
1 /*
2 Syren -- a lightweight downloader for Linux/BSD/MacOSX
3 inspired by Axel Copyright 2001-2002 Wilmer van der Gaast
4 version 0.0.6 (atomic alien)
5 coded by Ketmar // Avalon Group
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License with
18 the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL;
19 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
20 Suite 330, Boston, MA 02111-1307 USA
23 Syren HTTP headers list
25 #ifndef _SYREN_HDRS_C
26 #define _SYREN_HDRS_C
29 #include "syren_hdrs.h"
32 static void SyHdrClearItem (TSyKVListItem *key) {
33 TSyKVList *cc;
35 if (!key) return;
36 cc = key->udata;
37 if (cc) { SyKVListFree(cc); key->udata = NULL; }
41 static char *SyHdrCookieGetName (const char *cval) {
42 const char *s = cval;
44 if (!cval) return NULL;
45 while (*s && (unsigned char)(*s) > ' ' && (unsigned char)(*s) != '=') s++;
46 if (s == cval) return NULL;
47 return SyStrNew(cval, s-cval);
51 static TSyKVListItem *SyHdrFindCookieField (const TSyHdrs *hdr) {
52 TSyKVListItem *item;
54 if (!hdr || !hdr->fields || hdr->type == SY_HDR_INVALID) return NULL;
55 item = hdr->fields->first; while (item && !item->udata) item = item->next;
56 return item;
60 TSyHdrs *SyHdrNew (void) {
61 TSyHdrs *hdr = calloc(1, sizeof(TSyHdrs));
63 if (!hdr) return NULL;
64 hdr->fields = SyKVListNew();
65 if (!hdr->fields) { free(hdr); return NULL; }
66 hdr->code = -1; hdr->type = SY_HDR_INVALID;
67 return hdr;
71 void SyHdrFree (TSyHdrs *hdr) {
72 if (!hdr) return;
73 SyHdrClear(hdr, SY_HDR_INVALID); SyKVListFree(hdr->fields);
74 free(hdr);
78 void SyHdrClear (TSyHdrs *hdr, TSyHdrType type) {
79 TSyKVListItem *key;
80 if (!hdr) return;
81 if (hdr->fields) {
82 key = hdr->fields->first;
83 while (key) { SyHdrClearItem(key); key = key->next; }
84 SyKVListClear(hdr->fields);
86 if (hdr->firstLine) { free(hdr->firstLine); hdr->firstLine = NULL; }
87 hdr->code = -1; hdr->type = type;
91 static TSyKVListItem *SyHdrAddField (TSyHdrs *hdr, const char *kname, const char *value, int *newKey) {
92 TSyKVListItem *item;
94 if (!hdr || !hdr->fields || hdr->type == SY_HDR_INVALID) return NULL;
95 if (newKey) *newKey = 0;
96 if (!strcasecmp(kname, "Set-Cookie") || !strcasecmp(kname, "Set-Cookie2") ||
97 !strcasecmp(kname, "Cookie") || !strcasecmp(kname, "Cookie2")) {
98 item = SyKVListSet(hdr->fields, kname, NULL, newKey); if (!item) return NULL;
99 if (!item->udata) item->udata = SyKVListNew();
100 if (!item->udata) { SyKVListDelete(hdr->fields, kname); return NULL; }
101 ((TSyKVList *)(item->udata))->casesens = 1;
102 } else item = SyKVListSet(hdr->fields, kname, value, newKey); if (!item) return NULL;
103 return item;
107 TSyResult SyHdrDeleteField (TSyHdrs *hdr, const char *name) {
108 TSyKVListItem *item;
110 if (!hdr || !hdr->fields || hdr->type == SY_HDR_INVALID || !name || !name[0]) return SY_ERROR;
111 item = SyKVListFind(hdr->fields, name); if (!item) return SY_ERROR;
112 SyHdrClearItem(item);
113 return SyKVListDelete(hdr->fields, name);
117 char *SyHdrGetFieldValue (const TSyHdrs *hdr, const char *name) {
118 TSyKVListItem *item;
120 if (!hdr || !hdr->fields || hdr->type == SY_HDR_INVALID || !name || !name[0]) return NULL;
121 item = SyKVListFind(hdr->fields, name); if (!item) return NULL;
122 if (item->udata) return NULL; /* see cookie functions */
123 return SyStrDup(item->value);
127 /* set field; correctly processes "Set-Cookie" and "Cookie" */
128 TSyResult SyHdrSetFieldValue (TSyHdrs *hdr, const char *name, const char *value) {
129 char *s; int newKey;
130 TSyKVList *cc;
131 TSyKVListItem *item;
133 if (!hdr || !hdr->fields || hdr->type == SY_HDR_INVALID || !name || !name[0] || !value) return SY_ERROR;
134 while (*value && (unsigned char)(*value) <= ' ') value++; /*if (!value[0]) return SY_ERROR;*/
135 item = SyHdrAddField(hdr, name, value, &newKey); if (!item) return SY_ERROR;
136 if (item->udata) {
137 s = SyHdrCookieGetName(value);
138 if (!s) { if (newKey) SyHdrDeleteField(hdr, name); return SY_ERROR; }
139 cc = item->udata;
140 item = SyKVListSet(cc, s, value, NULL);
141 free(s);
142 if (!item) { if (newKey) SyHdrDeleteField(hdr, name); return SY_ERROR; }
144 return SY_OK;
148 TSyKVList *SyHdrFindCookieList (const TSyHdrs *hdr) {
149 TSyKVListItem *item = SyHdrFindCookieField(hdr);
151 if (item) return (TSyKVList *)item->udata;
152 return NULL;
156 void SyHdrDeleteCookie (TSyHdrs *hdr, const char *name) {
157 SyKVListDelete(SyHdrFindCookieList(hdr), name);
161 /* value must be full value (with 'path', 'domain', etc) */
162 TSyResult SyHdrSetCookie (TSyHdrs *hdr, const char *value) {
163 TSyKVListItem *item = SyHdrFindCookieField(hdr);
164 return SyHdrSetFieldValue(hdr,
165 item?item->key:(hdr->type==SY_HDR_REQUEST?"Cookie":"Set-Cookie"),
166 value);
170 /* add line, parse it, set "code" if necessary */
171 TSyResult SyHdrAddLine (TSyHdrs *hdr, const char *line) {
172 char *s, *n;
173 TSyKVListItem *item;
174 TSyKVList *cc;
175 TSyResult res = SY_OK;
177 if (!hdr || !hdr->fields || hdr->type == SY_HDR_INVALID || !line) return SY_ERROR;
178 if (!line[0]) return SY_OK; /* ignore empty lines */
179 if (hdr->firstLine) {
180 /* "name: value" pair or multiline */
181 if ((unsigned char)(*line) <= ' ') {
182 /* multiline header continues */
183 item = hdr->fields->last; if (!item) return SY_ERROR; /* nothing to continue */
184 if (item->udata) {
185 /* cookie... */
186 cc = item->udata;
187 item = cc->last; if (!item) return SY_ERROR; /* nothing to continue */
189 s = SySPrintf("%s%s", item->value?item->value:"", line); if (!s) return SY_ERROR;
190 if (item->value) free(item->value);
191 item->value = s;
192 } else {
193 /* "name: value" pair */
194 s = strchr(line, ':');
195 if (!s) return SY_ERROR;
196 n = SyStrNew(line, s-line); if (!n) return SY_ERROR;
197 SyStrTrim(n); if (!n[0]) { free(n); return SY_ERROR; }
198 s++; s = SyStrNew(s, -1); if (!s) { free(n); return SY_ERROR; }
199 SyStrTrim(s); if (!s[0]) { free(s); free(n); return SY_OK; }
200 res = SyHdrSetFieldValue(hdr, n, s);
201 free(s); free(n);
203 } else {
204 /* first line */
205 s = SyStrNew(line, -1); if (!s) return SY_ERROR;
206 hdr->firstLine = s;
207 if (hdr->type == SY_HDR_REPLY) {
208 /* parse reply code; bad code is error! */
209 /* hack for brain-damaged 'bandit' server */
210 while (*s) {
211 s = strstr(s, "HTTP/"); if (!s) break;
212 s += 5;
213 if (isdigit(*s) && s[1] == '.' && isdigit(s[2])) { s += 3; break; }
215 if (!s) return SY_ERROR;
216 while (*s && (unsigned char)(*s) > ' ') s++;
217 while (*s && (unsigned char)(*s) <= ' ') s++;
218 if (!isdigit(*s) || !isdigit(s[1]) || !isdigit(s[2])) return SY_ERROR;
219 if ((unsigned char)(s[3]) > ' ') return SY_ERROR;
220 hdr->code = (*s-'0')*100+(s[1]-'0')*10+(s[2]-'0');
223 return res;
227 #endif