1 /*
2 ** RESPONSE MANAGER
3 **
4 ** (c) COPYRIGHT MIT 1995.
5 ** Please first read the full copyright statement in the file COPYRIGH.
6 ** @(#) $Id$
7 **
8 ** Authors
9 ** HFN Henrik Frystyk, frystyk@w3.org
10 */
11
12 /* Library include files */
13 #include "wwwsys.h"
14 #include "WWWUtil.h"
15 #include "HTHeader.h"
16 #include "HTLib.h"
17 #include "HTWWWStr.h"
18 #include "HTResMan.h" /* Implemented here */
19
20 /* --------------------------------------------------------------------------*/
21 /* Create and delete the HTResponse Object */
22 /* --------------------------------------------------------------------------*/
23
HTResponse_new(void)24 PUBLIC HTResponse * HTResponse_new (void)
25 {
26 HTResponse * me;
27 if ((me = (HTResponse *) HT_CALLOC(1, sizeof(HTResponse))) == NULL)
28 HT_OUTOFMEM("HTResponse_new()");
29
30 /* Default content-* values */
31 me->content_type = WWW_UNKNOWN;
32 me->content_length = -1;
33
34 /* Default retry after value */
35 me->retry_after = -1;
36
37 /* By default a response is not cachable */
38 me->cachable = NO;
39
40 HTTRACE(CORE_TRACE, "Response.... Created %p\n" _ me);
41 return me;
42 }
43
HTResponse_delete(HTResponse * me)44 PUBLIC BOOL HTResponse_delete (HTResponse * me)
45 {
46 if (me) {
47 HTTRACE(CORE_TRACE, "Response.... Delete %p\n" _ me);
48
49 /* Access Authentication */
50 HT_FREE(me->realm);
51 HT_FREE(me->scheme);
52 if (me->challenge) HTAssocList_delete(me->challenge);
53
54 /* Connection headers */
55 if (me->connection) HTAssocList_delete(me->connection);
56
57 /* PEP Information */
58 if (me->protocol) HTAssocList_delete(me->protocol);
59 if (me->protocol_request) HTAssocList_delete(me->protocol_request);
60 if (me->protocol_info) HTAssocList_delete(me->protocol_info);
61
62 /* Cache control headers */
63 if (me->cache_control) HTAssocList_delete(me->cache_control);
64
65 /* Byte ranges */
66 if (me->byte_ranges) HTAssocList_delete(me->byte_ranges);
67
68 /* Transfer Encodings */
69 if (me->transfer_encoding) HTList_delete(me->transfer_encoding);
70
71 /* Trailers */
72 if (me->trailer) HTAssocList_delete(me->trailer);
73
74 /* Variants */
75 if (me->variants) HTAssocList_delete(me->variants);
76
77 /*
78 ** Only delete Content Type parameters and original headers if the
79 ** information is not used elsewhere, for example by the anchor
80 ** object.
81 */
82 if (!me->cached) {
83
84 /* Content type parameters */
85 if (me->type_parameters) HTAssocList_delete(me->type_parameters);
86
87 /* Content Encodings */
88 if (me->content_encoding) HTList_delete(me->content_encoding);
89
90 /* List of all headers */
91 if (me->headers) HTAssocList_delete(me->headers);
92 }
93
94 /* HTTP reason string */
95 if (me->reason) HT_FREE (me->reason);
96
97 HT_FREE(me);
98 return YES;
99 }
100 return NO;
101 }
102
103 /* --------------------------------------------------------------------------*/
104 /* Methods on the HTResponse Object */
105 /* --------------------------------------------------------------------------*/
106
107 /*
108 ** Redirection information
109 */
HTResponse_redirection(HTResponse * me)110 PUBLIC HTAnchor * HTResponse_redirection (HTResponse * me)
111 {
112 return (me ? me->redirectionAnchor : NULL);
113 }
114
HTResponse_setRedirection(HTResponse * me,HTAnchor * anchor)115 PUBLIC BOOL HTResponse_setRedirection (HTResponse * me, HTAnchor * anchor)
116 {
117 if (me && anchor) {
118 me->redirectionAnchor = (HTAnchor *) HTAnchor_parent(anchor);
119 return YES;
120 }
121 return NO;
122 }
123
124 /*
125 ** When to retry a response if HT_RETRY
126 ** Returns -1 if not available
127 */
HTResponse_retryTime(HTResponse * me)128 PUBLIC time_t HTResponse_retryTime (HTResponse * me)
129 {
130 return me ? me->retry_after : -1;
131 }
132
HTResponse_setRetryTime(HTResponse * me,time_t retry)133 PUBLIC BOOL HTResponse_setRetryTime (HTResponse * me, time_t retry)
134 {
135 if (me) {
136 me->retry_after = retry;
137 return YES;
138 }
139 return NO;
140 }
141
142 /*
143 ** Access Authentication Challenges
144 */
HTResponse_addChallenge(HTResponse * me,char * token,char * value)145 PUBLIC BOOL HTResponse_addChallenge (HTResponse * me,
146 char * token, char * value)
147 {
148 if (me) {
149 if (!me->challenge) me->challenge = HTAssocList_new();
150 return HTAssocList_addObject(me->challenge, token, value);
151 }
152 return NO;
153 }
154
HTResponse_deleteChallengeAll(HTResponse * me)155 PUBLIC BOOL HTResponse_deleteChallengeAll (HTResponse * me)
156 {
157 if (me && me->challenge) {
158 HTAssocList_delete(me->challenge);
159 me->challenge = NULL;
160 return YES;
161 }
162 return NO;
163 }
164
HTResponse_challenge(HTResponse * me)165 PUBLIC HTAssocList * HTResponse_challenge (HTResponse * me)
166 {
167 return (me ? me->challenge : NULL);
168 }
169
170 /*
171 ** Access Authentication Realms
172 */
HTResponse_setRealm(HTResponse * me,char * realm)173 PUBLIC BOOL HTResponse_setRealm (HTResponse * me, char * realm)
174 {
175 if (me && realm) {
176 StrAllocCopy(me->realm, realm);
177 return YES;
178 }
179 return NO;
180 }
181
HTResponse_realm(HTResponse * me)182 PUBLIC const char * HTResponse_realm (HTResponse * me)
183 {
184 return (me ? me->realm : NULL);
185 }
186
187 /*
188 ** Access Authentication Schemes
189 */
HTResponse_setScheme(HTResponse * me,char * scheme)190 PUBLIC BOOL HTResponse_setScheme (HTResponse * me, char * scheme)
191 {
192 if (me && scheme) {
193 StrAllocCopy(me->scheme, scheme);
194 return YES;
195 }
196 return NO;
197 }
198
HTResponse_scheme(HTResponse * me)199 PUBLIC const char * HTResponse_scheme (HTResponse * me)
200 {
201 return (me ? me->scheme : NULL);
202 }
203
204 /*
205 ** Connection Directives
206 */
HTResponse_addConnection(HTResponse * me,char * token,char * value)207 PUBLIC BOOL HTResponse_addConnection (HTResponse * me,
208 char * token, char * value)
209 {
210 if (me) {
211 if (!me->connection) me->connection = HTAssocList_new();
212 return HTAssocList_replaceObject(me->connection, token, value);
213 }
214 return NO;
215 }
216
HTResponse_deleteConnectionAll(HTResponse * me)217 PUBLIC BOOL HTResponse_deleteConnectionAll (HTResponse * me)
218 {
219 if (me && me->connection) {
220 HTAssocList_delete(me->connection);
221 me->connection = NULL;
222 return YES;
223 }
224 return NO;
225 }
226
HTResponse_connection(HTResponse * me)227 PUBLIC HTAssocList * HTResponse_connection (HTResponse * me)
228 {
229 return (me ? me->connection : NULL);
230 }
231
232 /*
233 ** PEP Protocol header
234 */
HTResponse_addProtocol(HTResponse * me,char * token,char * value)235 PUBLIC BOOL HTResponse_addProtocol (HTResponse * me,
236 char * token, char * value)
237 {
238 if (me) {
239 if (!me->protocol) me->protocol = HTAssocList_new();
240 return HTAssocList_addObject(me->protocol, token,value);
241 }
242 return NO;
243 }
244
HTResponse_deleteProtocolAll(HTResponse * me)245 PUBLIC BOOL HTResponse_deleteProtocolAll (HTResponse * me)
246 {
247 if (me && me->protocol) {
248 HTAssocList_delete(me->protocol);
249 me->protocol = NULL;
250 return YES;
251 }
252 return NO;
253 }
254
HTResponse_protocol(HTResponse * me)255 PUBLIC HTAssocList * HTResponse_protocol (HTResponse * me)
256 {
257 return (me ? me->protocol : NULL);
258 }
259
260 /*
261 ** PEP Protocol Info header
262 */
HTResponse_addProtocolInfo(HTResponse * me,char * token,char * value)263 PUBLIC BOOL HTResponse_addProtocolInfo (HTResponse * me,
264 char * token, char * value)
265 {
266 if (me) {
267 if (!me->protocol_info) me->protocol_info = HTAssocList_new();
268 return HTAssocList_addObject(me->protocol_info, token,value);
269 }
270 return NO;
271 }
272
HTResponse_deleteProtocolInfoAll(HTResponse * me)273 PUBLIC BOOL HTResponse_deleteProtocolInfoAll (HTResponse * me)
274 {
275 if (me && me->protocol_info) {
276 HTAssocList_delete(me->protocol_info);
277 me->protocol_info = NULL;
278 return YES;
279 }
280 return NO;
281 }
282
HTResponse_protocolInfo(HTResponse * me)283 PUBLIC HTAssocList * HTResponse_protocolInfo (HTResponse * me)
284 {
285 return (me ? me->protocol_info : NULL);
286 }
287
288 /*
289 ** PEP Protocol request header
290 */
HTResponse_addProtocolRequest(HTResponse * me,char * token,char * value)291 PUBLIC BOOL HTResponse_addProtocolRequest (HTResponse * me,
292 char * token, char * value)
293 {
294 if (me) {
295 if (!me->protocol_request) me->protocol_request = HTAssocList_new();
296 return HTAssocList_addObject(me->protocol_request, token,value);
297 }
298 return NO;
299 }
300
HTResponse_deleteProtocolRequestAll(HTResponse * me)301 PUBLIC BOOL HTResponse_deleteProtocolRequestAll (HTResponse * me)
302 {
303 if (me && me->protocol_request) {
304 HTAssocList_delete(me->protocol_request);
305 me->protocol_request = NULL;
306 return YES;
307 }
308 return NO;
309 }
310
HTResponse_protocolRequest(HTResponse * me)311 PUBLIC HTAssocList * HTResponse_protocolRequest (HTResponse * me)
312 {
313 return (me ? me->protocol_request : NULL);
314 }
315
316 /*
317 ** Cache control directives received in the response
318 */
HTResponse_deleteCacheControlAll(HTResponse * me)319 PUBLIC BOOL HTResponse_deleteCacheControlAll (HTResponse * me)
320 {
321 if (me && me->cache_control) {
322 HTAssocList_delete(me->cache_control);
323 me->cache_control = NULL;
324 return YES;
325 }
326 return NO;
327 }
328
HTResponse_cacheControl(HTResponse * me)329 PUBLIC HTAssocList * HTResponse_cacheControl (HTResponse * me)
330 {
331 return (me ? me->cache_control : NULL);
332 }
333
HTResponse_addCacheControl(HTResponse * me,char * token,char * value)334 PUBLIC BOOL HTResponse_addCacheControl (HTResponse * me,
335 char * token, char * value)
336 {
337 if (me) {
338 if (!me->cache_control)
339 me->cache_control=HTAssocList_new();
340 return HTAssocList_replaceObject(me->cache_control,
341 token, value);
342 }
343 return NO;
344 }
345
346 /*
347 ** Check whether we can cache this object or not.
348 */
HTResponse_isCachable(HTResponse * me)349 PUBLIC HTCachable HTResponse_isCachable (HTResponse * me)
350 {
351 if (me) {
352
353 /* We may already have decided that this object is not cachable */
354 if (me->cachable == HT_NO_CACHE) return HT_NO_CACHE;
355
356 #if 0
357 /* We don't cache negotiated resources for the moment */
358 if (me->variants) return HT_NO_CACHE;
359 #endif
360
361 /*
362 ** Check if we should cache this object or not. We are very liberale
363 ** in that we cache everything except if we explicit are told not to
364 ** cache (no-store, no-cache). In all other cases we can get around
365 ** it by forcing revalidation
366 */
367 if (me->cache_control) {
368 char * token;
369 if ((token=HTAssocList_findObject(me->cache_control, "no-store")))
370 return HT_NO_CACHE;
371 if ((token=HTAssocList_findObject(me->cache_control, "no-cache")))
372 if (!*token) return HT_NO_CACHE;
373 }
374
375 /* Cache everything else */
376 return me->cachable;
377 }
378 return HT_NO_CACHE;
379 }
380
HTResponse_setCachable(HTResponse * me,HTCachable mode)381 PUBLIC BOOL HTResponse_setCachable (HTResponse * me, HTCachable mode)
382 {
383 if (me) {
384 me->cachable = mode;
385 return YES;
386 }
387 return NO;
388 }
389
HTResponse_isCached(HTResponse * me,BOOL mode)390 PUBLIC BOOL HTResponse_isCached (HTResponse * me, BOOL mode)
391 {
392 if (me) {
393 me->cached = mode;
394 return YES;
395 }
396 return NO;
397 }
398
HTResponse_maxAge(HTResponse * me)399 PUBLIC time_t HTResponse_maxAge (HTResponse * me)
400 {
401 if (me && me->cache_control) {
402 char * token = HTAssocList_findObject(me->cache_control, "max-age");
403 if (token) return atol(token);
404 }
405 return (time_t) -1;
406 }
407
HTResponse_mustRevalidate(HTResponse * me)408 PUBLIC BOOL HTResponse_mustRevalidate (HTResponse * me)
409 {
410 return me && me->cache_control &&
411 (HTAssocList_findObject(me->cache_control,
412 "must-revalidate") != NULL);
413 }
414
HTResponse_noCache(HTResponse * me)415 PUBLIC char * HTResponse_noCache (HTResponse * me)
416 {
417 return (me && me->cache_control) ?
418 HTAssocList_findObject(me->cache_control,
419 "no-cache") : NULL;
420 }
421
HTResponse_etag(HTResponse * me)422 PUBLIC char * HTResponse_etag (HTResponse * me)
423 {
424 if (me && me->headers) {
425 char * value = HTAssocList_findObject(me->headers, "etag");
426 char * etag = HTNextField(&value);
427 return etag;
428 }
429 return NULL;
430 }
431
432 /*
433 ** Byte ranges
434 */
HTResponse_deleteRangeAll(HTResponse * me)435 PUBLIC BOOL HTResponse_deleteRangeAll (HTResponse * me)
436 {
437 if (me && me->byte_ranges) {
438 HTAssocList_delete(me->byte_ranges);
439 me->byte_ranges = NULL;
440 return YES;
441 }
442 return NO;
443 }
444
HTResponse_addRange(HTResponse * me,char * unit,char * range)445 PUBLIC BOOL HTResponse_addRange (HTResponse * me, char * unit, char * range)
446 {
447 if (me) {
448 if (!me->byte_ranges) me->byte_ranges = HTAssocList_new();
449 return HTAssocList_addObject(me->byte_ranges, unit, range);
450 }
451 return NO;
452 }
453
HTResponse_range(HTResponse * me)454 PUBLIC HTAssocList * HTResponse_range (HTResponse * me)
455 {
456 return (me ? me->byte_ranges : NULL);
457 }
458
459 /*
460 ** Content Length
461 */
HTResponse_length(HTResponse * me)462 PUBLIC long int HTResponse_length (HTResponse * me)
463 {
464 return me ? me->content_length : -1;
465 }
466
HTResponse_setLength(HTResponse * me,long int length)467 PUBLIC void HTResponse_setLength (HTResponse * me, long int length)
468 {
469 if (me) me->content_length = length;
470 }
471
HTResponse_addLength(HTResponse * me,long int delta_length)472 PUBLIC void HTResponse_addLength (HTResponse * me, long int delta_length)
473 {
474 if (me) {
475 if (me->content_length < 0)
476 me->content_length = delta_length;
477 else
478 me->content_length += delta_length;
479 }
480 }
481
482 /*
483 ** Content-Type
484 */
HTResponse_format(HTResponse * me)485 PUBLIC HTFormat HTResponse_format (HTResponse * me)
486 {
487 return me ? me->content_type : NULL;
488 }
489
HTResponse_setFormat(HTResponse * me,HTFormat form)490 PUBLIC void HTResponse_setFormat (HTResponse * me, HTFormat form)
491 {
492 if (me) me->content_type = form;
493 }
494
HTResponse_formatParam(HTResponse * me)495 PUBLIC HTAssocList * HTResponse_formatParam (HTResponse * me)
496 {
497 return me ? me->type_parameters : NULL;
498 }
499
HTResponse_addFormatParam(HTResponse * me,const char * name,const char * value)500 PUBLIC BOOL HTResponse_addFormatParam (HTResponse * me,
501 const char * name, const char * value)
502 {
503 if (me) {
504 if (!me->type_parameters) me->type_parameters = HTAssocList_new();
505 return HTAssocList_replaceObject(me->type_parameters, name, value);
506 }
507 return NO;
508 }
509
510 /*
511 ** Charset parameter to Content-Type
512 */
HTResponse_charset(HTResponse * me)513 PUBLIC HTCharset HTResponse_charset (HTResponse * me)
514 {
515 if (me && me->type_parameters) {
516 char * charset = HTAssocList_findObject(me->type_parameters,"charset");
517 return HTAtom_for(charset);
518 }
519 return NULL;
520 }
521
HTResponse_setCharset(HTResponse * me,HTCharset charset)522 PUBLIC BOOL HTResponse_setCharset (HTResponse * me, HTCharset charset)
523 {
524 return HTResponse_addFormatParam(me, "charset", HTAtom_name(charset));
525 }
526
527 /*
528 ** Content Encoding
529 */
HTResponse_addEncoding(HTResponse * me,HTEncoding encoding)530 PUBLIC BOOL HTResponse_addEncoding (HTResponse * me, HTEncoding encoding)
531 {
532 if (me && encoding) {
533 if (!me->content_encoding) me->content_encoding = HTList_new();
534 return HTList_addObject(me->content_encoding, encoding);
535 }
536 return NO;
537 }
538
HTResponse_encoding(HTResponse * me)539 PUBLIC HTList * HTResponse_encoding (HTResponse * me)
540 {
541 return me ? me->content_encoding : NULL;
542 }
543
544 /*
545 ** Transfer Encoding
546 */
HTResponse_addTransfer(HTResponse * me,HTEncoding transfer)547 PUBLIC BOOL HTResponse_addTransfer (HTResponse * me, HTEncoding transfer)
548 {
549 if (me && transfer) {
550 if (!me->transfer_encoding) me->transfer_encoding = HTList_new();
551 return HTList_addObject(me->transfer_encoding, transfer);
552 }
553 return NO;
554 }
555
HTResponse_transfer(HTResponse * me)556 PUBLIC HTList * HTResponse_transfer (HTResponse * me)
557 {
558 return me ? me->transfer_encoding : NULL;
559 }
560
561 /*
562 ** Content Transfer Encoding
563 */
HTResponse_contentTransferEncoding(HTResponse * me)564 PUBLIC HTEncoding HTResponse_contentTransferEncoding (HTResponse * me)
565 {
566 return me ? me->cte : NULL;
567 }
568
HTResponse_setContentTransferEncoding(HTResponse * me,HTEncoding transfer)569 PUBLIC BOOL HTResponse_setContentTransferEncoding (HTResponse * me, HTEncoding transfer)
570 {
571 if (me) {
572 me->cte = transfer;
573 return YES;
574 }
575 return NO;
576 }
577
HTResponse_addVariant(HTResponse * me,char * token,char * value)578 PUBLIC BOOL HTResponse_addVariant (HTResponse * me, char * token, char * value)
579 {
580 if (me) {
581 if (!me->variants) me->variants =HTAssocList_new();
582 return HTAssocList_replaceObject (me->variants, token, value);
583 }
584 return NO;
585 }
586
HTResponse_deleteVariantAll(HTResponse * me)587 PUBLIC BOOL HTResponse_deleteVariantAll (HTResponse * me)
588 {
589 if (me && me->variants) {
590 HTAssocList_delete(me->variants);
591 me->variants = NULL;
592 return YES;
593 }
594 return NO;
595 }
596
HTResponse_variant(HTResponse * me)597 PUBLIC HTAssocList * HTResponse_variant (HTResponse * me)
598 {
599 return (me ? me->variants : NULL);
600 }
601
602 /*
603 ** Trailers
604 */
HTResponse_addTrailer(HTResponse * me,char * token,char * value)605 PUBLIC BOOL HTResponse_addTrailer (HTResponse * me,
606 char * token, char * value)
607 {
608 if (me) {
609 if (!me->trailer) me->trailer = HTAssocList_new();
610 return HTAssocList_addObject(me->trailer, token, value);
611 }
612 return NO;
613 }
614
HTResponse_deleteTrailerAll(HTResponse * me)615 PUBLIC BOOL HTResponse_deleteTrailerAll (HTResponse * me)
616 {
617 if (me && me->trailer) {
618 HTAssocList_delete(me->trailer);
619 me->trailer = NULL;
620 return YES;
621 }
622 return NO;
623 }
624
HTResponse_trailer(HTResponse * me)625 PUBLIC HTAssocList * HTResponse_trailer (HTResponse * me)
626 {
627 return (me ? me->trailer : NULL);
628 }
629
630
631 /*
632 ** Original header information
633 */
HTResponse_addHeader(HTResponse * me,char * token,char * value)634 PUBLIC BOOL HTResponse_addHeader (HTResponse * me,
635 char * token, char * value)
636 {
637 if (me) {
638 if (!me->headers) me->headers = HTAssocList_new();
639 return HTAssocList_addObject(me->headers, token, value);
640 }
641 return NO;
642 }
643
HTResponse_deleteHeaderAll(HTResponse * me)644 PUBLIC BOOL HTResponse_deleteHeaderAll (HTResponse * me)
645 {
646 if (me && me->headers) {
647 HTAssocList_delete(me->headers);
648 me->headers = NULL;
649 return YES;
650 }
651 return NO;
652 }
653
HTResponse_header(HTResponse * me)654 PUBLIC HTAssocList * HTResponse_header (HTResponse * me)
655 {
656 return (me ? me->headers : NULL);
657 }
658
HTResponse_handOverHeader(HTResponse * me)659 PUBLIC HTAssocList * HTResponse_handOverHeader (HTResponse * me)
660 {
661 HTAssocList * headers = NULL;
662 if (me) {
663 headers = me->headers;
664 me->headers = NULL;
665 me->type_parameters = NULL; /* @@@ */
666 }
667 return headers;
668 }
669
670 /*
671 ** HTTP reason string
672 */
HTResponse_reason(HTResponse * me)673 PUBLIC char * HTResponse_reason (HTResponse * me)
674 {
675 if (me) {
676 return me->reason;
677 }
678 return NULL;
679 }
680
HTResponse_setReason(HTResponse * me,char * reason)681 PUBLIC BOOL HTResponse_setReason (HTResponse * me, char * reason)
682 {
683 if (me && reason && *reason) {
684 StrAllocCopy(me->reason, reason);
685 return YES;
686 }
687 return NO;
688 }
689
690