- fix typo
[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 http_request_datashare *_http_request_datashare_global_get(void)
36 {
37 return &http_request_datashare_global;
38 }
39
40 PHP_MINIT_FUNCTION(http_request_datashare)
41 {
42 curl_lock_data val;
43
44 zend_hash_init(&http_request_datashare_options, 4, NULL, NULL, 1);
45 #define ADD_DATASHARE_OPT(name, opt) \
46 val = opt; \
47 zend_hash_add(&http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL)
48 ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE);
49 ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS);
50 ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION);
51 ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT);
52
53 http_request_datashare_init_ex(&http_request_datashare_global, 1);
54
55 return SUCCESS;
56 }
57
58 PHP_MSHUTDOWN_FUNCTION(http_request_datashare)
59 {
60 http_request_datashare_dtor(&http_request_datashare_global);
61 zend_hash_destroy(&http_request_datashare_options);
62
63 return SUCCESS;
64 }
65
66 PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC)
67 {
68 int i;
69 zend_bool free_share;
70
71 if ((free_share = !share)) {
72 share = pemalloc(sizeof(http_request_datashare), persistent);
73 }
74 memset(share, 0, sizeof(http_request_datashare));
75
76 HTTP_CHECK_CURL_INIT(share->ch, curl_share_init(), ;);
77 if (!share->ch) {
78 if (free_share) {
79 pefree(share, persistent);
80 }
81 return NULL;
82 }
83
84 if ((share->persistent = persistent)) {
85 share->locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(http_request_datashare_lock), 1);
86 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
87 share->locks[i].mx = tsrm_mutex_alloc();
88 }
89 curl_share_setopt(share->ch, CURLSHOPT_LOCKFUNC, http_request_datashare_lock_func);
90 curl_share_setopt(share->ch, CURLSHOPT_UNLOCKFUNC, http_request_datashare_unlock_func);
91 curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share);
92 }
93
94 zend_llist_init(&share->handles, sizeof(zval *), ZVAL_PTR_DTOR, persistent);
95
96 return share;
97 }
98
99 PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC)
100 {
101 CURLcode rc;
102 getObjectEx(http_request_object, obj, request);
103
104 if (obj->share) {
105 if (obj->share == share) {
106 return SUCCESS;
107 } else if (SUCCESS != http_request_datashare_detach(obj->share, request)) {
108 return FAILURE;
109 }
110 }
111
112 if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, share->ch))) {
113 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));
114 return FAILURE;
115 }
116
117 obj->share = share;
118 ZVAL_ADDREF(request);
119 zend_llist_add_element(&share->handles, (void *) &request);
120
121 return SUCCESS;
122 }
123
124 PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC)
125 {
126 CURLcode rc;
127 getObjectEx(http_request_object, obj, request);
128
129 if (!obj->share) {
130 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
131 } else if (obj->share != share) {
132 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
133 } else if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL))) {
134 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));
135 } else {
136 obj->share = NULL;
137 zend_llist_del_element(&share->handles, request, http_request_datashare_compare_handles);
138 return SUCCESS;
139 }
140 return FAILURE;
141 }
142
143 PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC)
144 {
145 zval **r;
146
147 while ((r = zend_llist_get_first(&share->handles))) {
148 http_request_datashare_detach(share, *r);
149 }
150 }
151
152 PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC)
153 {
154 int i;
155
156 zend_llist_destroy(&share->handles);
157 curl_share_cleanup(share->ch);
158 if (share->persistent) {
159 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
160 tsrm_mutex_free(share->locks[i].mx);
161 }
162 pefree(share->locks, 1);
163 }
164 }
165
166 PHP_HTTP_API void _http_request_datashare_free(http_request_datashare **share TSRMLS_DC)
167 {
168 http_request_datashare_dtor(*share);
169 pefree(*share, (*share)->persistent);
170 *share = NULL;
171 }
172
173 PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC)
174 {
175 curl_lock_data *opt;
176 CURLSHcode rc;
177
178 if (SUCCESS == zend_hash_find(&http_request_datashare_options, (char *) option, option_len + 1, (void *) &opt)) {
179 if (CURLSHE_OK == (rc = curl_share_setopt(share->ch, enable ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, *opt))) {
180 return SUCCESS;
181 }
182 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not %s sharing of %s data: %s", enable ? "enable" : "disable", option, curl_share_strerror(rc));
183 }
184 return FAILURE;
185 }
186
187 static int http_request_datashare_compare_handles(void *h1, void *h2)
188 {
189 return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
190 }
191
192 static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
193 {
194 http_request_datashare *share = (http_request_datashare *) userptr;
195
196 /* TSRM can't distinguish shared/exclusive locks */
197 tsrm_mutex_lock(share->locks[data].mx);
198 share->locks[data].ch = handle;
199 }
200
201 static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr)
202 {
203 http_request_datashare *share = (http_request_datashare *) userptr;
204
205 if (share->locks[data].ch == handle) {
206 tsrm_mutex_unlock(share->locks[data].mx);
207 }
208 }
209
210 #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
211
212
213 /*
214 * Local variables:
215 * tab-width: 4
216 * c-basic-offset: 4
217 * End:
218 * vim600: noet sw=4 ts=4 fdm=marker
219 * vim<600: noet sw=4 ts=4
220 */
221