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
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
);
64 SyMessage(pfn
, SY_MSG_ERROR
, "can't parse reply header string");
70 SyMessage(pfn
, SY_MSG_ERROR
, "empty reply headers");
73 SyMessage(pfn
, SY_MSG_NOTICE
, " reply headers received; code: %i", hdrs
->code
);
78 /* -1: none or error */
79 int64_t SyHTTPGetSize (const TSyHdrs
*hdrs
) {
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");
90 t
= strcasestr(s
, "size");
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
++;
98 if (*t
== '"') { t
++; s
= t
; while (*s
&& *s
!= '"') s
++; }
99 else { s
= t
; while (*s
&& (*s
!= ' ' && *s
!= ';')) s
++; }
109 static TSyResult
SyHTTPAddAuth (TSyHdrs
*hdrs
, const char *astr
, const TSyURL
*url
) {
111 const char *user
, *pass
;
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
;
127 TSyResult
SyHTTPBuildQuery (TSyHdrs
*hdrs
, const char *method
, const TSyURL
*url
, const TSyURL
*proxy
) {
128 char port
[32], *tmp
, *s
;
131 if (!hdrs
) return SY_ERROR
;
133 SyHdrClear(hdrs
, SY_HDR_REQUEST
);
134 if (!url
) return SY_ERROR
;
136 if (url
->port
!= 80) sprintf(port
, ":%i", url
->port
); else *port
= '\0';
137 mt
= (method
&& *method
)?method
:"GET";
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);
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
;
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
;
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
);
163 TSyResult
SyHTTPAddRange (TSyHdrs
*hdrs
, int from
, int to
) {
166 if (!hdrs
) return SY_ERROR
;
168 if (to
< 0) return SY_OK
;
171 if (to
>= 0 && to
< from
) return SY_ERROR
;
173 if (from
> 0) s
= SySPrintf("Range: bytes=%i-%i", from
, to
);
174 else s
= SySPrintf("Range: bytes=-%i", to
);
176 if (from
> 0) s
= SySPrintf("Range: bytes=%i-", from
); else return SY_OK
;
178 res
= SyHdrAddLine(hdrs
, s
); free(s
);
183 /* FIXME: hide password! */
184 TSyResult
SyHTTPSendQuery (TSySocket
*fd
, const TSyHdrs
*hdrs
, const TSyPrintStr
*pfn
) {
185 TSyKVListItem
*item
, *ci
;
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
;
192 item
= hdrs
->fields
->first
;
195 if (cc
&& cc
->count
) {
198 if (SyTCPSendLine(pfn
, 1, fd
, "%s: %s", item
->key
, ci
->value
) != SY_OK
) return SY_ERROR
;
202 if (SyTCPSendLine(pfn
, 1, fd
, "%s: %s", item
->key
, item
->value
) != SY_OK
) return SY_ERROR
;
206 return SyTCPSendLine(pfn
, 0, fd
, "");