]>
Commit | Line | Data |
---|---|---|
7c887d1f | 1 | |
2 | /* | |
2b6662ba | 3 | * $Id: HttpHdrContRange.cc,v 1.13 2001/01/12 00:37:13 wessels Exp $ |
7c887d1f | 4 | * |
5 | * DEBUG: section 68 HTTP Content-Range Header | |
6 | * AUTHOR: Alex Rousskov | |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
7c887d1f | 10 | * |
2b6662ba | 11 | * Squid is the result of efforts by numerous individuals from |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the CREDITS file for full details. | |
7c887d1f | 19 | * |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
7c887d1f | 34 | */ |
35 | ||
36 | #include "squid.h" | |
37 | ||
b644367b | 38 | /* |
39 | * Currently only byte ranges are supported | |
40 | * | |
41 | * Content-Range = "Content-Range" ":" content-range-spec | |
42 | * content-range-spec = byte-content-range-spec | |
43 | * byte-content-range-spec = bytes-unit SP | |
44 | * ( byte-range-resp-spec | "*") "/" | |
45 | * ( entity-length | "*" ) | |
46 | * byte-range-resp-spec = first-byte-pos "-" last-byte-pos | |
47 | * entity-length = 1*DIGIT | |
48 | */ | |
7c887d1f | 49 | |
50 | ||
51 | /* local constants */ | |
52 | #define range_spec_unknown ((size_t)-1) | |
53 | ||
54 | /* local routines */ | |
55 | #define known_spec(s) ((s) != range_spec_unknown) | |
56 | #define size_min(a,b) ((a) <= (b) ? (a) : (b)) | |
57 | #define size_diff(a,b) ((a) >= (b) ? ((a)-(b)) : 0) | |
58 | ||
59 | /* globals */ | |
60 | ||
61 | /* parses range-resp-spec and inits spec, returns true on success */ | |
62 | static int | |
b644367b | 63 | httpHdrRangeRespSpecParseInit(HttpHdrRangeSpec * spec, const char *field, int flen) |
7c887d1f | 64 | { |
65 | const char *p; | |
66 | assert(spec); | |
67 | spec->offset = spec->length = range_spec_unknown; | |
68 | if (flen < 2) | |
69 | return 0; | |
70 | /* is spec given ? */ | |
71 | if (*field == '*') | |
de336bbe | 72 | return 1; |
7c887d1f | 73 | /* check format, must be %d-%d */ |
b644367b | 74 | if (!((p = strchr(field, '-')) && (p - field < flen))) { |
de336bbe | 75 | debug(68, 2) ("invalid (no '-') resp-range-spec near: '%s'\n", field); |
7c887d1f | 76 | return 0; |
77 | } | |
78 | /* parse offset */ | |
de336bbe | 79 | if (!httpHeaderParseSize(field, &spec->offset)) |
b644367b | 80 | return 0; |
7c887d1f | 81 | p++; |
82 | /* do we have last-pos ? */ | |
83 | if (p - field < flen) { | |
9bc73deb | 84 | ssize_t last_pos; |
7c887d1f | 85 | if (!httpHeaderParseSize(p, &last_pos)) |
86 | return 0; | |
b644367b | 87 | spec->length = size_diff(last_pos + 1, spec->offset); |
7c887d1f | 88 | } |
89 | /* we managed to parse, check if the result makes sence */ | |
90 | if (known_spec(spec->length) && !spec->length) { | |
de336bbe | 91 | debug(68, 2) ("invalid range (%d += %d) in resp-range-spec near: '%s'\n", |
92 | spec->offset, spec->length, field); | |
7c887d1f | 93 | return 0; |
94 | } | |
95 | return 1; | |
96 | } | |
97 | ||
98 | static void | |
b644367b | 99 | httpHdrRangeRespSpecPackInto(const HttpHdrRangeSpec * spec, Packer * p) |
7c887d1f | 100 | { |
101 | if (!known_spec(spec->offset) || !known_spec(spec->length)) | |
102 | packerPrintf(p, "*"); | |
103 | else | |
f20ea194 | 104 | packerPrintf(p, "bytes %d-%d", |
b644367b | 105 | spec->offset, spec->offset + spec->length - 1); |
7c887d1f | 106 | } |
107 | ||
108 | /* | |
109 | * Content Range | |
110 | */ | |
111 | ||
112 | HttpHdrContRange * | |
9bc73deb | 113 | httpHdrContRangeCreate(void) |
7c887d1f | 114 | { |
115 | HttpHdrContRange *r = memAllocate(MEM_HTTP_HDR_CONTENT_RANGE); | |
116 | r->spec.offset = r->spec.length = range_spec_unknown; | |
117 | r->elength = range_spec_unknown; | |
118 | return r; | |
119 | } | |
120 | ||
121 | HttpHdrContRange * | |
122 | httpHdrContRangeParseCreate(const char *str) | |
123 | { | |
124 | HttpHdrContRange *r = httpHdrContRangeCreate(); | |
125 | if (!httpHdrContRangeParseInit(r, str)) { | |
126 | httpHdrContRangeDestroy(r); | |
127 | r = NULL; | |
128 | } | |
129 | return r; | |
130 | } | |
131 | ||
132 | /* returns true if ranges are valid; inits HttpHdrContRange */ | |
133 | int | |
b644367b | 134 | httpHdrContRangeParseInit(HttpHdrContRange * range, const char *str) |
7c887d1f | 135 | { |
136 | const char *p; | |
137 | assert(range && str); | |
de336bbe | 138 | debug(68, 8) ("parsing content-range field: '%s'\n", str); |
139 | /* check range type */ | |
140 | if (strncasecmp(str, "bytes ", 6)) | |
141 | return 0; | |
142 | str += 6; | |
7c887d1f | 143 | /* split */ |
144 | if (!(p = strchr(str, '/'))) | |
145 | return 0; | |
146 | if (*str == '*') | |
147 | range->spec.offset = range->spec.length = range_spec_unknown; | |
b644367b | 148 | else if (!httpHdrRangeRespSpecParseInit(&range->spec, str, p - str)) |
7c887d1f | 149 | return 0; |
150 | p++; | |
151 | if (*p == '*') | |
152 | range->elength = range_spec_unknown; | |
b644367b | 153 | else if (!httpHeaderParseSize(p, &range->elength)) |
7c887d1f | 154 | return 0; |
b644367b | 155 | debug(68, 8) ("parsed content-range field: %d-%d / %d\n", |
156 | range->spec.offset, range->spec.offset + range->spec.length - 1, | |
de336bbe | 157 | range->elength); |
7c887d1f | 158 | return 1; |
159 | } | |
160 | ||
161 | void | |
b644367b | 162 | httpHdrContRangeDestroy(HttpHdrContRange * range) |
7c887d1f | 163 | { |
164 | assert(range); | |
db1cd23c | 165 | memFree(range, MEM_HTTP_HDR_CONTENT_RANGE); |
7c887d1f | 166 | } |
167 | ||
168 | HttpHdrContRange * | |
169 | httpHdrContRangeDup(const HttpHdrContRange * range) | |
170 | { | |
171 | HttpHdrContRange *dup; | |
172 | assert(range); | |
173 | dup = httpHdrContRangeCreate(); | |
174 | *dup = *range; | |
175 | return dup; | |
176 | } | |
177 | ||
178 | void | |
179 | httpHdrContRangePackInto(const HttpHdrContRange * range, Packer * p) | |
180 | { | |
181 | assert(range && p); | |
182 | httpHdrRangeRespSpecPackInto(&range->spec, p); | |
183 | if (!known_spec(range->elength)) | |
184 | packerPrintf(p, "/*"); | |
185 | else | |
186 | packerPrintf(p, "/%d", range->elength); | |
187 | } | |
d192d11f | 188 | |
189 | void | |
9bc73deb | 190 | httpHdrContRangeSet(HttpHdrContRange * cr, HttpHdrRangeSpec spec, ssize_t ent_len) |
d192d11f | 191 | { |
192 | assert(cr && ent_len >= 0); | |
193 | cr->spec = spec; | |
194 | cr->elength = ent_len; | |
195 | } |