1 /*
2    Basic cookie support for neon
3    Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public
16    License along with this library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18    MA 02111-1307, USA
19 
20 */
21 
22 /* A nice demo of hooks, since it doesn't need any external
23  * interface to muck with the stored states.
24  */
25 
26 #include "config.h"
27 
28 #ifdef HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif
31 
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #endif
35 
36 #include <time.h>
37 
38 #include "ne_cookies.h"
39 
40 #include "ne_request.h"
41 #include "ne_string.h"
42 #include "ne_alloc.h"
43 
44 #define COOKIE_ID "http://www.webdav.org/neon/hooks/cookies"
45 
set_cookie_hdl(void * userdata,const char * value)46 static void set_cookie_hdl(void *userdata, const char *value)
47 {
48     char **pairs = pair_string(value, ';', '=', "\"'", " \r\n\t");
49     ne_cookie *cook;
50     ne_cookie_cache *cache = userdata;
51     int n;
52 
53     /* Check sanity */
54     if (pairs[0] == NULL || pairs[1] == NULL) {
55 	/* yagaboo */
56 	return;
57     }
58 
59     NE_DEBUG(NE_DBG_HTTP, "Got cookie name=%s\n", pairs[0]);
60 
61     /* Search for a cookie of this name */
62     NE_DEBUG(NE_DBG_HTTP, "Searching for existing cookie...\n");
63     for (cook = cache->cookies; cook != NULL; cook = cook->next) {
64 	if (strcasecmp(cook->name, pairs[0]) == 0) {
65 	    break;
66 	}
67     }
68 
69     if (cook == NULL) {
70 	NE_DEBUG(NE_DBG_HTTP, "New cookie.\n");
71 	cook = ne_malloc(sizeof *cook);
72 	memset(cook, 0, sizeof *cook);
73 	cook->name = ne_strdup(ne_shave(pairs[0], " \t\r\n"));
74 	cook->next = cache->cookies;
75 	cache->cookies = cook;
76     } else {
77 	/* Free the old value */
78 	ne_free(cook->value);
79     }
80 
81     cook->value = ne_strdup(ne_shave(pairs[1], " \t\r\n"));
82 
83     for (n = 2; pairs[n] != NULL; n+=2) {
84         if (!pairs[n+1]) continue;
85 	NE_DEBUG(NE_DBG_HTTP, "Cookie parm %s=%s\n", pairs[n], pairs[n+1]);
86 	if (strcasecmp(pairs[n], "path") == 0) {
87 	    cook->path = ne_strdup(pairs[n+1]);
88 	} else if (strcasecmp(pairs[n], "max-age") == 0) {
89 	    int t = atoi(pairs[n+1]);
90 	    cook->expiry = time(NULL) + (time_t)t;
91 	} else if (strcasecmp(pairs[n], "domain") == 0) {
92 	    cook->domain = ne_strdup(pairs[n+1]);
93 	}
94     }
95 
96     NE_DEBUG(NE_DBG_HTTP, "End of parms.\n");
97 
98     pair_string_free(pairs);
99 }
100 
create(ne_request * req,void * session,const char * method,const char * uri)101 static void create(ne_request *req, void *session,
102 		   const char *method, const char *uri)
103 {
104     ne_cookie_cache *cache = session;
105     ne_add_response_header_handler(req, "Set-Cookie", set_cookie_hdl, cache);
106 }
107 
108 /* Just before sending the request: let them add headers if they want */
pre_send(ne_request * req,void * session,ne_buffer * request)109 static void pre_send(ne_request *req, void *session, ne_buffer *request)
110 {
111     ne_cookie_cache *cache = session;
112     ne_cookie *cook;
113 
114     if (cache->cookies == NULL) {
115 	return;
116     }
117 
118     ne_buffer_zappend(request, "Cookie: ");
119 
120     for (cook = cache->cookies; cook != NULL; cook=cook->next) {
121 	ne_buffer_concat(request, cook->name, "=", cook->value, NULL);
122 	if (cook->next != NULL) {
123 	    ne_buffer_zappend(request, "; ");
124 	}
125     }
126 
127     ne_buffer_zappend(request, "\r\n");
128 }
129 
130 /* Register cookie handling for given session using given cache. */
ne_cookie_register(ne_session * sess,ne_cookie_cache * cache)131 void ne_cookie_register(ne_session *sess, ne_cookie_cache *cache)
132 {
133     ne_hook_create_request(sess, create, cache);
134     ne_hook_pre_send(sess, pre_send, cache);
135 }
136 
137