4983377dd0e3a34ebfb1fbdeda2e8e736f1d24b3
[m6w6/ext-http] / http_request_datashare_api.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_CURL
16 #include "php_http.h"
17
18 #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
19
20 #include "php_http_api.h"
21 #include "php_http_request_datashare_api.h"
22 #include "php_http_request_api.h"
23 #include "php_http_request_object.h"
24
25 #ifndef HAVE_CURL_SHARE_STRERROR
26 # define curl_share_strerror(dummy) "unknown error"
27 #endif
28
29 static HashTable http_request_datashare_options;
30 static http_request_datashare http_request_datashare_global;
31 static int http_request_datashare_compare_handles(void *h1, void *h2);
32 static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr);
33 static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr);
34
35 PHP_MINIT_FUNCTION(http_request_datashare)
36 {
37 curl_lock_data val;
38
39 zend_hash_init(&http_request_datashare_options, 4, NULL, NULL, 1);
40 #define ADD_DATASHARE_OPT(name, opt) \
41 val = opt; \
42 zend_hash_add(&http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL)
43 ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE);
44 ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS);
45 ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION);
46 ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT);
47
48 http_request_datashare_init_ex(&http_request_datashare_global, 1);
49
50 return SUCCESS;
51 }
52
53 PHP_MSHUTDOWN_FUNCTION(http_request_datashare)
54 {
55 http_request_datashare_dtor(&http_request_datashare_global);
56 zend_hash_destroy(&http_request_datashare_options);
57
58 return SUCCESS;
59 }
60
61 PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC)
62 {
63 int i;
64 zend_bool free_share;
65
66 if ((free_share = !share)) {
67 share = pemalloc(sizeof(http_request_datashare), persistent);
68 }
69 memset(share, 0, sizeof(http_request_datashare));
70
71 HTTP_CHECK_CURL_INIT(share->ch, curl_share_init(), ;);
72 if (!share->ch) {
73 if (free_share) {
74 pefree(share, persistent);
75 }
76 return NULL;
77 }
78
79 if ((share->persistent = persistent)) {
80 share->locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(http_request_datashare_lock), 1);
81 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
82 share->locks[i].mx = tsrm_mutex_alloc();
83 }
84 curl_share_setopt(share->ch, CURLSHOPT_LOCKFUNC, http_request_datashare_lock_func);
85 curl_share_setopt(share->ch, CURLSHOPT_UNLOCKFUNC, http_request_datashare_unlock_func);
86 curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share);
87 }
88
89 zend_llist_init(&share->handles, sizeof(zval *), ZVAL_PTR_DTOR, persistent);
90
91 return share;
92 }
93
94 PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC)
95 {
96 CURLcode rc;
97 getObjectEx(http_request_object, obj, request);
98
99 if (obj->share) {
100 if (obj->share == share) {
101 return SUCCESS;
102 } else if (SUCCESS != http_request_datashare_detach(obj->share, request)) {
103 return FAILURE;
104 }
105 }
106
107 if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, share->ch))) {
108 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not attach HttpRequest object(#%d) to the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc));
109 return FAILURE;
110 }
111
112 obj->share = share;
113 ZVAL_ADDREF(request);
114 zend_llist_add_element(&share->handles, (void *) &request);
115
116 return SUCCESS;
117 }
118
119 PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC)
120 {
121 CURLcode rc;
122 getObjectEx(http_request_object, obj, request);
123
124 if (!obj->share) {
125 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
126 } else if (obj->share != share) {
127 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
128 } else if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL))) {
129 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not detach HttpRequest object(#%d) from the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc));
130 } else {
131 obj->share = NULL;
132 zend_llist_del_element(&share->handles, request, http_request_datashare_compare_handles);
133 return SUCCESS;
134 }
135 return FAILURE;
136 }
137
138 PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC)
139 {
140 zval **r;
141
142 while ((r = zend_llist_get_first(&share->handles))) {
143 http_request_datashare_detach(share, *r);
144 }
145 }
146
147 PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC)
148 {
149 int i;
150
151 zend_llist_destroy(&share->handles);
152 curl_share_cleanup(share->ch);
153 if (share->persistent) {
154 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
155 tsrm_mutex_free(share->locks[i].mx);
156 }
157 pefree(share->locks, 1);
158 }
159 }
160
161 PHP_HTTP_API void _http_request_datashare_free(http_request_datashare **share TSRMLS_DC)
162 {
163 http_request_datashare_dtor(*share);
164 pefree(*share, (*share)->persistent);
165 *share = NULL;
166 }
167
168 PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC)
169 {
170 curl_lock_data *opt;
171 CURLSHcode rc;
172
173 if (SUCCESS == zend_hash_find(&http_request_datashare_options, (char *) option, option_len + 1, (void *) &opt)) {
174 if (CURLSHE_OK == (rc = curl_share_setopt(share->ch, enable ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, *opt))) {
175 return SUCCESS;
176 }
177 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not %s sharing of %s data: %s", enable ? "enable" : "disable", option, curl_share_strerror(rc));
178 }
179 return FAILURE;
180 }
181
182 static int http_request_datashare_compare_handles(void *h1, void *h2)
183 {
184 return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
185 }
186
187 static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
188 {
189 http_request_datashare *share = (http_request_datashare *) userptr;
190
191 /* TSRM can't distinguish shared/exclusive locks */
192 tsrm_mutex_lock(share->locks[data].mx);
193 share->locks[data].ch = handle;
194 }
195
196 static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr)
197 {
198 http_request_datashare *share = (http_request_datashare *) userptr;
199
200 if (share->locks[data].ch == handle) {
201 tsrm_mutex_unlock(share->locks[data].mx);
202 }
203 }
204
205 #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
206
207
208 /*
209 * Local variables:
210 * tab-width: 4
211 * c-basic-offset: 4
212 * End:
213 * vim600: noet sw=4 ts=4 fdm=marker
214 * vim<600: noet sw=4 ts=4
215 */
216