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