parsing "size" field in content-disposition
[syren.git] / src / syren_http.c
bloba321dc41589a2f215734d071de706b47a1c11189
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 utilities
25 #ifndef _SYREN_HTTP_C
26 #define _SYREN_HTTP_C
28 #include "syren_http.h"
31 /* return ptr to next line */
32 static char *SyHTTPFixLine (char *curstr) {
33 char *nl = curstr, *res;
35 while (*nl && *nl != '\n') nl++;
36 res = nl+(*nl?1:0);
37 *nl = '\0';
38 if (nl > curstr && *(nl-1) == '\r') *(nl-1) = '\0';
40 return res;
44 TSyResult SyHTTPReadHeaders (TSyHdrs *hdrs, TSySocket *fd, const TSyPrintStr *pfn) {
45 char *hdrbuf, *curstr, *nextstr;
46 TSyResult res;
48 SyMessage(pfn, SY_MSG_NOTICE, "reading reply headers");
49 if (!hdrs) return SY_ERROR;
50 SyHdrClear(hdrs, SY_HDR_REPLY);
51 if (!fd || fd->fd < 0) return SY_ERROR;
52 hdrbuf = SyTCPReceiveHdrs(fd, 65536);
53 if (!hdrbuf) {
54 SyMessage(pfn, SY_MSG_ERROR, "error receiving reply headers");
55 return SY_ERROR;
57 curstr = hdrbuf;
58 while (*curstr) {
59 nextstr = SyHTTPFixLine(curstr);
60 if (!nextstr[0]) break;
61 SyMessage(pfn, SY_MSG_NOTICE, " %s", curstr);
62 res = SyHdrAddLine(hdrs, curstr);
63 if (res != SY_OK) {
64 SyMessage(pfn, SY_MSG_ERROR, "can't parse reply header string");
65 return SY_ERROR;
67 curstr = nextstr;
69 if (hdrs->code < 0) {
70 SyMessage(pfn, SY_MSG_ERROR, "empty reply headers");
71 return SY_ERROR;
73 SyMessage(pfn, SY_MSG_NOTICE, " reply headers received; code: %i", hdrs->code);
74 return SY_OK;
78 /* -1: none or error */
79 int64_t SyHTTPGetSize (const TSyHdrs *hdrs) {
80 int64_t res;
81 char *s, *t;
82 char *buf = SyHdrGetFieldValue(hdrs, "content-length");
83 res = SyStr2Long(buf); if (buf) free(buf);
84 if (res >= 0) return res;
85 /*Content-Disposition: attachment; filename="textpattern-4.0.6.tar.gz"; size = "304354"*/
86 buf = SyHdrGetFieldValue(hdrs, "Content-Disposition");
87 if (!buf) return -1;
88 s = buf;
89 while (*s) {
90 t = strcasestr(s, "size");
91 if (!t) break;
92 if (t != buf && isalnum(*(t-1))) { s = t+1; continue; }
93 t += 4; if (*t && isalnum(*t)) { s = t; continue; }
94 while (*t && *t <= ' ') t++;
95 if (*t != '=') { s = t; continue; }
96 t++; while (*t && *t <= ' ') t++;
97 if (!(*t)) break;
98 if (*t == '"') { t++; s = t; while (*s && *s != '"') s++; }
99 else { s = t; while (*s && (*s != ' ' && *s != ';')) s++; }
100 *s = '\0';
101 res = SyStr2Long(t);
102 break;
104 free(buf);
105 return res;
109 static TSyResult SyHTTPAddAuth (TSyHdrs *hdrs, const char *astr, const TSyURL *url) {
110 TSyResult res;
111 const char *user, *pass;
112 char *tmp, *s;
114 user = url->user; pass = url->pass;
115 if ((user && *user) || (pass && *pass)) {
116 tmp = SyBuildAuthStr(user, pass); if (!tmp) return SY_ERROR;
117 s = SySPrintf(astr, tmp);
118 free(tmp); if (!s) return SY_ERROR;
119 res = SyHdrAddLine(hdrs, s); free(s);
120 if (res != SY_OK) return SY_ERROR;
123 return SY_OK;
127 TSyResult SyHTTPBuildQuery (TSyHdrs *hdrs, const char *method, const TSyURL *url, const TSyURL *proxy) {
128 char port[32], *tmp, *s;
129 const char *mt;
130 TSyResult res;
131 if (!hdrs) return SY_ERROR;
133 SyHdrClear(hdrs, SY_HDR_REQUEST);
134 if (!url) return SY_ERROR;
135 /* query string */
136 if (url->port != 80) sprintf(port, ":%i", url->port); else *port = '\0';
137 mt = (method && *method)?method:"GET";
138 if (proxy) {
139 /*if (*url->user || *url->pass)
140 s = SySPrintf("%s %s://%s:%s@%s%s", mt, url->protostr, url->user, url->pass, url->host, port);
141 else*/
142 s = SySPrintf("%s %s://%s%s", mt, url->protostr, url->host, port);
143 } else s = SySPrintf("%s ", mt);
144 if (!s) return SY_ERROR;
145 tmp = SySPrintf("%s%s%s%s%s HTTP/1.0", s, url->dir, url->file, url->query, url->anchor);
146 free(s); if (!tmp) return SY_ERROR;
147 res = SyHdrAddLine(hdrs, tmp); free(tmp);
148 if (res != SY_OK) return SY_ERROR;
149 /* auth */
150 if (proxy) {
151 if (SyHTTPAddAuth(hdrs, "Proxy-Authorization: Basic %s", proxy) != SY_OK) return SY_ERROR;
153 if (SyHTTPAddAuth(hdrs, "Authorization: Basic %s", url) != SY_OK) return SY_ERROR;
154 /* host */
155 if (url->port != 80) s = SySPrintf("Host: %s:%i", url->host, url->port); /* don't add 443 for HTTPS? */
156 else s = SySPrintf("Host: %s", url->host);
157 if (!s) return SY_ERROR;
158 res = SyHdrAddLine(hdrs, s); free(s);
159 return res;
163 TSyResult SyHTTPAddRange (TSyHdrs *hdrs, int from, int to) {
164 TSyResult res;
165 char *s;
166 if (!hdrs) return SY_ERROR;
167 if (from <= 0) {
168 if (to < 0) return SY_OK;
169 from = 0;
171 if (to >= 0 && to < from) return SY_ERROR;
172 if (to >= 0) {
173 if (from > 0) s = SySPrintf("Range: bytes=%i-%i", from, to);
174 else s = SySPrintf("Range: bytes=-%i", to);
175 } else {
176 if (from > 0) s = SySPrintf("Range: bytes=%i-", from); else return SY_OK;
178 res = SyHdrAddLine(hdrs, s); free(s);
179 return res;
183 /* FIXME: hide password! */
184 TSyResult SyHTTPSendQuery (TSySocket *fd, const TSyHdrs *hdrs, const TSyPrintStr *pfn) {
185 TSyKVListItem *item, *ci;
186 TSyKVList *cc;
188 if (!hdrs || !hdrs->fields || hdrs->type == SY_HDR_INVALID) return SY_ERROR;
189 if (!hdrs->firstLine) { SyMessage(pfn, SY_MSG_ERROR, "incomplete header"); return SY_ERROR; }
190 if (SyTCPSendLine(pfn, 1, fd, "%s", hdrs->firstLine) != SY_OK) return SY_ERROR;
191 /* auth */
192 item = hdrs->fields->first;
193 while (item) {
194 cc = item->udata;
195 if (cc && cc->count) {
196 ci = cc->first;
197 while (ci) {
198 if (SyTCPSendLine(pfn, 1, fd, "%s: %s", item->key, ci->value) != SY_OK) return SY_ERROR;
199 ci = ci->next;
201 } else {
202 if (SyTCPSendLine(pfn, 1, fd, "%s: %s", item->key, item->value) != SY_OK) return SY_ERROR;
204 item = item->next;
206 return SyTCPSendLine(pfn, 0, fd, "");
210 #endif