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 // Vampire Avalon
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
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
++;
38 if (nl
> curstr
&& *(nl
-1) == '\r') *(nl
-1) = '\0';
44 TSyResult
SyHTTPReadHeaders (TSyHdrs
*hdrs
, TSySocket
*fd
, const TSyPrintStr
*pfn
) {
45 char *hdrbuf
, *curstr
, *nextstr
;
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);
54 SyMessage(pfn
, SY_MSG_ERROR
, "error receiving reply headers");
59 nextstr
= SyHTTPFixLine(curstr
);
60 if (!nextstr
[0]) break;
61 SyMessage(pfn
, SY_MSG_NOTICE
, " %s", curstr
);
62 res
= SyHdrAddLine(hdrs
, curstr
);
65 SyMessage(pfn
, SY_MSG_ERROR
, "can't parse reply header string");
72 SyMessage(pfn
, SY_MSG_ERROR
, "empty reply headers");
75 SyMessage(pfn
, SY_MSG_NOTICE
, " reply headers received; code: %i", hdrs
->code
);
80 /* -1: none or error */
81 int64_t SyHTTPGetSize (const TSyHdrs
*hdrs
) {
84 char *buf
= SyHdrGetFieldValue(hdrs
, "content-length");
85 res
= SyStr2Long(buf
); if (buf
) free(buf
);
86 if (res
>= 0) return res
;
87 /*Content-Disposition: attachment; filename="textpattern-4.0.6.tar.gz"; size = "304354"*/
88 buf
= SyHdrGetFieldValue(hdrs
, "Content-Disposition");
92 t
= strcasestr(s
, "size");
94 if (t
!= buf
&& isalnum(*(t
-1))) { s
= t
+1; continue; }
95 t
+= 4; if (*t
&& isalnum(*t
)) { s
= t
; continue; }
96 while (*t
&& *t
<= ' ') t
++;
97 if (*t
!= '=') { s
= t
; continue; }
98 t
++; while (*t
&& *t
<= ' ') t
++;
100 if (*t
== '"') { t
++; s
= t
; while (*s
&& *s
!= '"') s
++; }
101 else { s
= t
; while (*s
&& (*s
!= ' ' && *s
!= ';')) s
++; }
109 //Content-Range: bytes 2759580-21263647/21263648
110 buf
= SyHdrGetFieldValue(hdrs
, "Content-Range");
112 t
= strchr(buf
, '/');
113 if (!strcasestr(buf
, "bytes") || !t
|| !t
[1]) { free(buf
); return -1; }
114 for (s
= ++t
; *s
; s
++) if (!isdigit(*s
)) { free(buf
); return -1; }
121 static TSyResult
SyHTTPAddAuth (TSyHdrs
*hdrs
, const char *astr
, const TSyURL
*url
) {
123 const char *user
, *pass
;
126 user
= url
->user
; pass
= url
->pass
;
127 if ((user
&& *user
) || (pass
&& *pass
)) {
128 tmp
= SyBuildAuthStr(user
, pass
); if (!tmp
) return SY_ERROR
;
129 s
= SySPrintf(astr
, tmp
);
130 free(tmp
); if (!s
) return SY_ERROR
;
131 res
= SyHdrAddLine(hdrs
, s
); free(s
);
132 if (res
!= SY_OK
) return SY_ERROR
;
139 TSyResult
SyHTTPBuildQuery (TSyHdrs
*hdrs
, const char *method
, const TSyURL
*url
, const TSyURL
*proxy
) {
140 char port
[32], *tmp
, *s
;
143 if (!hdrs
) return SY_ERROR
;
145 SyHdrClear(hdrs
, SY_HDR_REQUEST
);
146 if (!url
) return SY_ERROR
;
148 if (url
->port
!= 80) sprintf(port
, ":%i", url
->port
); else *port
= '\0';
149 mt
= (method
&& *method
)?method
:"GET";
151 /*if (*url->user || *url->pass)
152 s = SySPrintf("%s %s://%s:%s@%s%s", mt, url->protostr, url->user, url->pass, url->host, port);
154 s
= SySPrintf("%s %s://%s%s", mt
, url
->protostr
, url
->host
, port
);
155 } else s
= SySPrintf("%s ", mt
);
156 if (!s
) return SY_ERROR
;
157 tmp
= SySPrintf("%s%s%s%s%s HTTP/1.1", s
, url
->dir
, url
->file
, url
->query
, url
->anchor
);
158 free(s
); if (!tmp
) return SY_ERROR
;
159 res
= SyHdrAddLine(hdrs
, tmp
); free(tmp
);
160 if (res
!= SY_OK
) return SY_ERROR
;
163 if (SyHTTPAddAuth(hdrs
, "Proxy-Authorization: Basic %s", proxy
) != SY_OK
) return SY_ERROR
;
165 if (SyHTTPAddAuth(hdrs
, "Authorization: Basic %s", url
) != SY_OK
) return SY_ERROR
;
167 if ((url
->proto
== SY_PROTO_HTTPS
&& url
->port
!= 443) ||
168 (url
->proto
!= SY_PROTO_HTTPS
&& url
->port
!= 80))
169 s
= SySPrintf("Host: %s:%i", url
->host
, url
->port
); /* don't add 443 for HTTPS too */
171 s
= SySPrintf("Host: %s", url
->host
);
172 if (!s
) return SY_ERROR
;
173 res
= SyHdrAddLine(hdrs
, s
); free(s
);
175 SyHdrAddLine(hdrs
, "X-Tracking-Choice: do-not-track");
176 SyHdrAddLine(hdrs
, "DNT: 1");
177 SyHdrAddLine(hdrs
, "X-Do-Not-Track: 1");
183 TSyResult
SyHTTPAddRange (TSyHdrs
*hdrs
, int from
, int to
) {
186 if (!hdrs
) return SY_ERROR
;
188 if (to
< 0) return SY_OK
;
191 if (to
>= 0 && to
< from
) return SY_ERROR
;
193 if (from
> 0) s
= SySPrintf("Range: bytes=%i-%i", from
, to
);
194 else s
= SySPrintf("Range: bytes=-%i", to
);
196 if (from
> 0) s
= SySPrintf("Range: bytes=%i-", from
); else return SY_OK
;
198 res
= SyHdrAddLine(hdrs
, s
); free(s
);
203 /* FIXME: hide password! */
204 TSyResult
SyHTTPSendQuery (TSySocket
*fd
, const TSyHdrs
*hdrs
, const TSyPrintStr
*pfn
) {
205 TSyKVListItem
*item
, *ci
;
208 if (!hdrs
|| !hdrs
->fields
|| hdrs
->type
== SY_HDR_INVALID
) return SY_ERROR
;
209 if (!hdrs
->firstLine
) { SyMessage(pfn
, SY_MSG_ERROR
, "incomplete header"); return SY_ERROR
; }
210 if (SyTCPSendLine(pfn
, 1, fd
, "%s", hdrs
->firstLine
) != SY_OK
) return SY_ERROR
;
212 item
= hdrs
->fields
->first
;
215 if (cc
&& cc
->count
) {
218 if (SyTCPSendLine(pfn
, 1, fd
, "%s: %s", item
->key
, ci
->value
) != SY_OK
) return SY_ERROR
;
222 if (SyTCPSendLine(pfn
, 1, fd
, "%s: %s", item
->key
, item
->value
) != SY_OK
) return SY_ERROR
;
226 return SyTCPSendLine(pfn
, 0, fd
, "");