1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 8 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2020 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Ruslan Osmanov <osmanov@php.net> |
16 +----------------------------------------------------------------------+
17 */
18 #include "../src/common.h"
19 #include "../src/util.h"
20 #include "../src/priv.h"
21 #include "http.h"
22 #include "zend_exceptions.h"
23
24 /* {{{ Private */
25
26 /* {{{ _check_http_req_ptr */
27 #define _check_http_req_ptr(http_req) \
28 { \
29 if (!http_req->ptr) { \
30 php_error_docref(NULL, E_WARNING, \
31 "Invalid HTTP request object"); \
32 RETURN_FALSE; \
33 } \
34 }
35 /* }}} */
36
37 /* {{{ _check_http_req_type */
38 #define _check_http_req_type(type) \
getContents()39 { \
40 if (type & ~(PHP_EVENT_REQ_HEADER_INPUT | PHP_EVENT_REQ_HEADER_OUTPUT)) { \
41 php_error_docref(NULL, E_WARNING, \
42 "Invalid HTTP request type passed: %ld", type); \
43 RETURN_FALSE; \
44 } \
45 }
46 /* }}} */
47
48 /* {{{ _get_http_req_headers */
49 static zend_always_inline struct evkeyvalq *_get_http_req_headers(const php_event_http_req_t *http_req, const zend_long type)
50 {
51 struct evkeyvalq *headers;
52
53 if (type == PHP_EVENT_REQ_HEADER_OUTPUT) {
54 headers = evhttp_request_get_output_headers(http_req->ptr);
55 } else {
56 headers = evhttp_request_get_input_headers(http_req->ptr);
57 }
58
59 return headers;
60 }
61 /* }}} */
62
63 /* {{{ _req_handler */
64 static void _req_handler(struct evhttp_request *req, void *arg)
65 {
66 php_event_http_req_t *http_req = (php_event_http_req_t *)arg;
67 zend_fcall_info fci;
68 zval argv[2];
69 zval retval;
70 zval zcallable;
71 zend_string *func_name;
72
73 PHP_EVENT_ASSERT(http_req && http_req->ptr);
74
75 /* Protect against accidental destruction of the func name before zend_call_function() finished */
76 ZVAL_COPY(&zcallable, &http_req->cb.func_name);
77
78 if (!zend_is_callable(&zcallable, IS_CALLABLE_STRICT, &func_name)) {
79 zend_string_release(func_name);
80 return;
81 }
82 zend_string_release(func_name);
83
84 /* Call userspace function according to
85 * proto void callback(EventHttpRequest req, mixed data); */
86
87 /* req == NULL means timeout */
88 if (req == NULL || Z_ISUNDEF(http_req->self)) {
89 ZVAL_NULL(&argv[0]);
90 } else {
91 ZVAL_COPY(&argv[0], &http_req->self);
92 }
93
94 if (Z_ISUNDEF(http_req->data)) {
95 ZVAL_NULL(&argv[1]);
96 } else {
97 ZVAL_COPY(&argv[1], &http_req->data);
98 }
99
100 fci.size = sizeof(fci);
101 #ifdef HAVE_PHP_ZEND_FCALL_INFO_FUNCTION_TABLE
102 fci.function_table = EG(function_table);
103 #endif
104 ZVAL_COPY_VALUE(&fci.function_name, &zcallable);
105 fci.object = NULL;
106 fci.retval = &retval;
107 fci.params = argv;
108 fci.param_count = 2;
109 fci.no_separation = 1;
110 #ifdef HAVE_PHP_ZEND_FCALL_INFO_SYMBOL_TABLE
111 fci.symbol_table = NULL;
112 #endif
113
114 /* Tell Libevent that we will free the request ourselves(evhttp_request_free in the free-storage handler)*/
115 /*evhttp_request_own(http_req->ptr);*/
116
117 if (zend_call_function(&fci, &http_req->cb.fci_cache) == SUCCESS) {
118 if (!Z_ISUNDEF(retval)) {
119 zval_ptr_dtor(&retval);
120 }
121 } else {
122 php_error_docref(NULL, E_WARNING, "Failed to invoke http request handler");
123 }
124
125 zval_ptr_dtor(&zcallable);
126
127 zval_ptr_dtor(&argv[0]);
128 zval_ptr_dtor(&argv[1]);
129 }
130 /* }}} */
131
132 /* }}} */
133
134 /*{{{ proto int EventHttpRequest::__sleep */
135 PHP_METHOD(EventHttpRequest, __sleep)
136 {
137 zend_throw_exception_ex(php_event_get_exception(), 0, "EventHttpRequest instances are not serializable");
138 }
139 /*}}}*/
140
141 /*{{{ proto int EventHttpRequest::__wakeup */
142 PHP_METHOD(EventHttpRequest, __wakeup)
143 {
144 zend_throw_exception_ex(php_event_get_exception(), 0, "EventHttpRequest instances are not serializable");
145 }
146 /*}}}*/
147
148 /* {{{ proto EventHttpRequest::__construct(callable callback[, mixed data = NULL]); */
149 PHP_METHOD(EventHttpRequest, __construct)
150 {
151 zval *zself = getThis();
152 php_event_http_req_t *http_req;
153 zval *zcb;
154 zval *zarg = NULL;
155 struct evhttp_request *req;
156
157
158 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|z!", &zcb, &zarg) == FAILURE) {
159 return;
160 }
161
162 http_req = Z_EVENT_HTTP_REQ_OBJ_P(zself);
163
164 req = evhttp_request_new(_req_handler, (void *)http_req);
165 PHP_EVENT_ASSERT(req);
166
167 /* Tell Libevent that we will free the request ourselves(evhttp_request_free in the free-storage handler)
168 * XXX Not sure if it's really needed here though. */
169 evhttp_request_own(req);
170 http_req->ptr = req;
171
172 ZVAL_COPY(&http_req->self, zself);
173 if (zarg) {
174 ZVAL_COPY(&http_req->data, zarg);
175 } else {
176 ZVAL_UNDEF(&http_req->data);
177 }
178 php_event_copy_callback(&http_req->cb, zcb);
179 }
180 /* }}} */
181
182 /* {{{ proto void EventHttpRequest::free(void);
183 * Frees the object and removes associated events. */
184 PHP_METHOD(EventHttpRequest, free)
185 {
186 php_event_http_req_t *http_req;
187
188 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
189 PHP_EVENT_ASSERT(http_req);
190
191 if (!http_req->ptr || http_req->internal) {
192 return;
193 }
194
195 if (http_req->ptr) {
196 /*
197 * We're not calling evhttp_request_free(http_req->ptr) because AFAIK
198 * Libevent handles the memory of evhttp_request all right.
199 *
200 * It just so happens that libevent invokes the function itself in
201 * evhttp_connection_cb_cleanup() despite the ownership of the request
202 * (thus causing a SEGFAULT). See bitbucket issue #3.
203 *
204 * By marking http_req as `internal` we prevent calling evhttp_request_free()
205 * within event_http_req_object_free_storage().
206 */
207 http_req->internal = 1;
208 /*http_req->ptr = NULL;*/
209 }
210
211 /* Do it once */
212 if (!Z_ISUNDEF(http_req->self)) {
213 zval_ptr_dtor(&http_req->self);
214 ZVAL_UNDEF(&http_req->self);
215 }
216 }
217 /* }}} */
218
219 /* {{{ proto int EventHttpRequest::getCommand(void);
220 * Returns the request command, one of EventHttpRequest::CMD_* constants. XXX Make property? */
221 PHP_METHOD(EventHttpRequest, getCommand)
222 {
223 php_event_http_req_t *http_req;
224
225 if (zend_parse_parameters_none() == FAILURE) {
226 return;
227 }
228
229 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
230
231 _check_http_req_ptr(http_req);
232
233 RETVAL_LONG(evhttp_request_get_command(http_req->ptr));
234 }
235 /* }}} */
236
237 /* {{{ proto string EventHttpRequest::getHost(void);
238 * Returns the request host. XXX make a property? */
239 PHP_METHOD(EventHttpRequest, getHost)
240 {
241 php_event_http_req_t *http_req;
242
243 if (zend_parse_parameters_none() == FAILURE) {
244 return;
245 }
246
247 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
248
249 _check_http_req_ptr(http_req);
250
251 RETVAL_STRING(evhttp_request_get_host(http_req->ptr));
252 }
253 /* }}} */
254
255 /* {{{ proto int EventHttpRequest::getUri(void);
256 * Returns the request URI. XXX make a property? */
257 PHP_METHOD(EventHttpRequest, getUri)
258 {
259 php_event_http_req_t *http_req;
260
261 if (zend_parse_parameters_none() == FAILURE) {
262 return;
263 }
264
265 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
266
267 _check_http_req_ptr(http_req);
268
269 RETVAL_STRING(evhttp_request_get_uri(http_req->ptr));
270 }
271 /* }}} */
272
273 /* {{{ proto int EventHttpRequest::getResponseCode(void);
274 * Returns the the response code. XXX make a property? */
275 PHP_METHOD(EventHttpRequest, getResponseCode)
276 {
277 php_event_http_req_t *http_req;
278
279 if (zend_parse_parameters_none() == FAILURE) {
280 return;
281 }
282
283 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
284
285 _check_http_req_ptr(http_req);
286
287 RETVAL_LONG(evhttp_request_get_response_code(http_req->ptr));
288 }
289 /* }}} */
290
291 /* {{{ proto array EventHttpRequest::getInputHeaders(void);
292 * Returns associative array of the input headers. */
293 PHP_METHOD(EventHttpRequest, getInputHeaders)
294 {
295 php_event_http_req_t *http_req;
296 struct evkeyvalq *headers;
297 struct evkeyval *header;
298
299 if (zend_parse_parameters_none() == FAILURE) {
300 return;
301 }
302
303 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
304
305 _check_http_req_ptr(http_req);
306
307 array_init(return_value);
308
309 headers = evhttp_request_get_input_headers(http_req->ptr);
310 for (header = headers->tqh_first; header;
311 header = header->next.tqe_next) {
312 add_assoc_string(return_value, header->key, header->value);
313 }
314
315
316 }
317 /* }}} */
318
319 /* {{{ proto array EventHttpRequest::getOutputHeaders(void);
320 * Returns associative array of the output headers. */
321 PHP_METHOD(EventHttpRequest, getOutputHeaders)
322 {
323 php_event_http_req_t *http_req;
324 struct evkeyvalq *headers;
325 struct evkeyval *header;
326
327 if (zend_parse_parameters_none() == FAILURE) {
328 return;
329 }
330
331 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
332
333 _check_http_req_ptr(http_req);
334
335 array_init(return_value);
336
337 headers = evhttp_request_get_output_headers(http_req->ptr);
338 for (header = headers->tqh_first; header;
339 header = header->next.tqe_next) {
340 add_assoc_string(return_value, header->key, header->value);
341 }
342 }
343 /* }}} */
344
345 /* {{{ proto EventBuffer EventHttpRequest::getInputBuffer(void);
346 * Returns input buffer. */
347 PHP_METHOD(EventHttpRequest, getInputBuffer)
348 {
349 php_event_http_req_t *http_req;
350 php_event_buffer_t *b;
351
352 if (zend_parse_parameters_none() == FAILURE) {
353 return;
354 }
355
356 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
357
358 _check_http_req_ptr(http_req);
359
360 PHP_EVENT_INIT_CLASS_OBJECT(return_value, php_event_buffer_ce);
361 b = Z_EVENT_BUFFER_OBJ_P(return_value);
362 b->buf = evhttp_request_get_input_buffer(http_req->ptr);
363 b->internal = 1;
364 }
365 /* }}} */
366
367 /* {{{ proto EventBuffer EventHttpRequest::getOutputBuffer(void);
368 * Returns output buffer. */
369 PHP_METHOD(EventHttpRequest, getOutputBuffer)
370 {
371 php_event_http_req_t *http_req;
372 php_event_buffer_t *b;
373
374 if (zend_parse_parameters_none() == FAILURE) {
375 return;
376 }
377
378 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
379
380 _check_http_req_ptr(http_req);
381
382 PHP_EVENT_INIT_CLASS_OBJECT(return_value, php_event_buffer_ce);
383 b = Z_EVENT_BUFFER_OBJ_P(return_value);
384 b->buf = evhttp_request_get_output_buffer(http_req->ptr);
385 b->internal = 1;
386 }
387 /* }}} */
388
389 #if LIBEVENT_VERSION_NUMBER >= 0x02001100
390 /* {{{ proto EventBufferEvent EventHttpRequest::getBufferEvent(void);
391 * Returns EventBufferEvent object on success, otherwise &null. */
392 PHP_METHOD(EventHttpRequest, getBufferEvent)
393 {
394 php_event_http_req_t *http_req;
395 struct evhttp_connection *conn;
396 php_event_bevent_t *bev;
397
398 if (zend_parse_parameters_none() == FAILURE) {
399 return;
400 }
401
402 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
403
404 _check_http_req_ptr(http_req);
405
406 conn = evhttp_request_get_connection(http_req->ptr);
407 if (conn == NULL) {
408 RETURN_NULL();
409 }
410
411 PHP_EVENT_INIT_CLASS_OBJECT(return_value, php_event_bevent_ce);
412 bev = Z_EVENT_BEVENT_OBJ_P(return_value);
413
414 bev->bevent = evhttp_connection_get_bufferevent(conn);
415 ZVAL_COPY(&bev->self, return_value);
416 ZVAL_UNDEF(&bev->input);
417 ZVAL_UNDEF(&bev->output);
418 bev->_internal = 1;
419 }
420 /* }}} */
421 #endif
422
423 /* {{{ proto EventHttpConnection EventHttpRequest::getConnection(void);
424 * Returns EventHttpConnection object.
425 *
426 * Warning! Libevent API allows http request objects not bound to any http connection.
427 * Therefore we can't unambiguously associate EventHttpRequest with EventHttpConnection.
428 * Thus, we construct EventHttpConnection object on-the-fly. Having no information about
429 * base, dns_base and connection-close callback, we just leave these fields unset.
430 *
431 * If somebody finds some way to return full-value EventHttpConnection object,
432 * please don't hesitate to make a pull request.
433 */
434 PHP_METHOD(EventHttpRequest, getConnection)
435 {
436 php_event_http_req_t *http_req;
437 struct evhttp_connection *conn;
438 php_event_http_conn_t *evcon;
439
440 if (zend_parse_parameters_none() == FAILURE) {
441 return;
442 }
443
444 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
445
446 _check_http_req_ptr(http_req);
447
448 conn = evhttp_request_get_connection(http_req->ptr);
449 if (conn == NULL) {
450 RETURN_NULL();
451 }
452
453 PHP_EVENT_INIT_CLASS_OBJECT(return_value, php_event_http_conn_ce);
454 evcon = Z_EVENT_HTTP_CONN_OBJ_P(return_value);
455
456 evcon->conn = conn;
457 evcon->internal = TRUE;
458 ZVAL_COPY(&evcon->self, return_value);
459
460 #if 0
461 ZVAL_UNDEF(&evcon->base);
462 ZVAL_UNDEF(&evcon->dns_base);
463 ZVAL_UNDEF(&evcon->data_closecb);
464 ZVAL_UNDEF(&evcon->cb_close.func_name);
465 #endif
466
467 #if 0
468 Z_TRY_ADDREF_P(return_value);
469 #endif
470 }
471 /* }}} */
472
473 /* {{{ proto void EventHttpRequest::closeConnection(void);
474 */
475 PHP_METHOD(EventHttpRequest, closeConnection)
476 {
477 php_event_http_req_t *http_req;
478 struct evhttp_connection *conn;
479
480 if (zend_parse_parameters_none() == FAILURE) {
481 return;
482 }
483
484 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
485
486 _check_http_req_ptr(http_req);
487
488 conn = evhttp_request_get_connection(http_req->ptr);
489 if (conn == NULL) {
490 return;
491 }
492 evhttp_connection_free(conn);
493 }
494 /* }}} */
495
496 /* {{{ proto void EventHttpRequest::sendError(int error[, string reason = NULL]);
497 * Send an HTML error message to the client.
498 */
499 PHP_METHOD(EventHttpRequest, sendError)
500 {
501 php_event_http_req_t *http_req;
502 zend_long error;
503 char *reason = NULL;
504 size_t reason_len;
505
506 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|s!",
507 &error, &reason, &reason_len) == FAILURE) {
508 return;
509 }
510
511 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
512
513 _check_http_req_ptr(http_req);
514
515 evhttp_send_error(http_req->ptr, error, reason);
516 }
517 /* }}} */
518
519 /* {{{ proto void EventHttpRequest::sendReply(int code, string reason[, EventBuffer buf=&null;]);
520 * Send an HTML reply to client.
521 *
522 * The body of the reply consists of data in <parameter>buf</parameter>. */
523 PHP_METHOD(EventHttpRequest, sendReply)
524 {
525 php_event_http_req_t *http_req;
526 zend_long code;
527 char *reason;
528 size_t reason_len;
529 zval *zbuf = NULL;
530 php_event_buffer_t *b;
531
532 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls|O!",
533 &code, &reason, &reason_len,
534 &zbuf, php_event_buffer_ce) == FAILURE) {
535 return;
536 }
537
538 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
539
540 _check_http_req_ptr(http_req);
541
542 if (zbuf) {
543 b = Z_EVENT_BUFFER_OBJ_P(zbuf);
544 PHP_EVENT_ASSERT(b->buf);
545 }
546
547 evhttp_send_reply(http_req->ptr, code, reason,
548 (zbuf ? b->buf : NULL));
549 }
550 /* }}} */
551
552 /* {{{ proto void EventHttpRequest::sendReplyChunk(EventBuffer buf);
553 * Send another data chunk as part of an ongoing chunked reply.
554 *
555 * After calling this method <parameter>buf</parameter> will be empty. */
556 PHP_METHOD(EventHttpRequest, sendReplyChunk)
557 {
558 php_event_http_req_t *http_req;
559 zval *zbuf;
560 php_event_buffer_t *b;
561
562 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O",
563 &zbuf, php_event_buffer_ce) == FAILURE) {
564 return;
565 }
566
567 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
568
569 _check_http_req_ptr(http_req);
570
571 if (zbuf) {
572 b = Z_EVENT_BUFFER_OBJ_P(zbuf);
573 PHP_EVENT_ASSERT(b->buf);
574 evhttp_send_reply_chunk(http_req->ptr, b->buf);
575 }
576 }
577 /* }}} */
578
579 /* {{{ proto void EventHttpRequest::sendReplyEnd(void);
580 * Complete a chunked reply, freeing the request as appropriate.
581 */
582 PHP_METHOD(EventHttpRequest, sendReplyEnd)
583 {
584 php_event_http_req_t *http_req;
585
586 if (zend_parse_parameters_none() == FAILURE) {
587 return;
588 }
589
590 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
591
592 _check_http_req_ptr(http_req);
593
594 evhttp_send_reply_end(http_req->ptr);
595 }
596 /* }}} */
597
598 /* {{{ proto void EventHttpRequest::sendReplyStart(int code, string reason);
599 * Initiate a reply that uses <literal>Transfer-Encoding</literal>
600 * <literal>chunked</literal>.
601 *
602 * This allows the caller to stream the reply back to the client and is useful
603 * when either not all of the reply data is immediately available or when
604 * sending very large replies.
605 *
606 * The caller needs to supply data chunks with
607 * <method>EventHttpRequest::sendReplyChunk</method> and complete the reply by
608 * calling <method>EventHttpRequest::sendReplyEnd</method>.
609 */
610 PHP_METHOD(EventHttpRequest, sendReplyStart)
611 {
612 php_event_http_req_t *http_req;
613 zend_long code;
614 char *reason;
615 size_t reason_len;
616
617 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls",
618 &code, &reason, &reason_len) == FAILURE) {
619 return;
620 }
621
622 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
623
624 _check_http_req_ptr(http_req);
625
626
627 evhttp_send_reply_start(http_req->ptr, code, reason);
628 }
629 /* }}} */
630
631 /* {{{ proto void EventHttpRequest::cancel(void);
632 * Cancels a pending HTTP request.
633 *
634 * Cancels an ongoing HTTP request. The callback associated with this request
635 * is not executed and the request object is freed. If the request is currently
636 * being processed, e.g. it is ongoing, the corresponding EventHttpConnection
637 * object is going to get reset.
638 *
639 * A request cannot be canceled if its callback has executed already. A request
640 * may be canceled reentrantly from its chunked callback.
641 */
642 PHP_METHOD(EventHttpRequest, cancel)
643 {
644 php_event_http_req_t *http_req;
645
646 if (zend_parse_parameters_none() == FAILURE) {
647 return;
648 }
649
650 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
651
652 _check_http_req_ptr(http_req);
653
654 evhttp_cancel_request(http_req->ptr);
655 }
656 /* }}} */
657
658 /* {{{ proto bool EventHttpRequest::addHeader(string key, string value, int type);
659 * Adds an HTTP header to the headers of the request.
660 * <parameter>type</parameter> is one of <literal>EventHttpRequest::*_HEADER</literal>
661 * constants.
662 */
663 PHP_METHOD(EventHttpRequest, addHeader)
664 {
665 php_event_http_req_t *http_req;
666 char *key;
667 char *value;
668 size_t key_len;
669 size_t value_len;
670 struct evkeyvalq *headers;
671 zend_long type;
672
673 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssl",
674 &key, &key_len, &value, &value_len, &type) == FAILURE) {
675 return;
676 }
677
678 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
679 _check_http_req_ptr(http_req);
680
681 headers = _get_http_req_headers(http_req, type);
682 PHP_EVENT_ASSERT(headers);
683
684
685 if (evhttp_add_header(headers, key, value)) {
686 RETURN_FALSE;
687 }
688 RETVAL_TRUE;
689 }
690 /* }}} */
691
692 /* {{{ proto void EventHttpRequest::clearHeaders(string key, string value);
693 * Removes all output headers from the header list of the request.
694 */
695 PHP_METHOD(EventHttpRequest, clearHeaders)
696 {
697 php_event_http_req_t *http_req;
698 struct evkeyvalq *out_headers;
699
700 if (zend_parse_parameters_none() == FAILURE) {
701 return;
702 }
703
704 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
705 _check_http_req_ptr(http_req);
706
707 out_headers = evhttp_request_get_output_headers(http_req->ptr);
708 PHP_EVENT_ASSERT(out_headers);
709
710 evhttp_clear_headers(out_headers);
711 }
712 /* }}} */
713
714 /* {{{ proto bool EventHttpRequest::removeHeader(string key, int type);
715 * Removes an HTTP header from the headers of the request.
716 * <parameter>type</parameter> is one of <literal>EventHttpRequest::*_HEADER</literal>
717 * constants.
718 */
719 PHP_METHOD(EventHttpRequest, removeHeader)
720 {
721 php_event_http_req_t *http_req;
722 char *key;
723 size_t key_len;
724 struct evkeyvalq *headers;
725 zend_long type;
726
727 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
728 &key, &key_len, &type) == FAILURE) {
729 return;
730 }
731
732 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
733
734 _check_http_req_ptr(http_req);
735
736 headers = _get_http_req_headers(http_req, type);
737 PHP_EVENT_ASSERT(headers);
738
739 if (evhttp_remove_header(headers, key)) {
740 RETURN_FALSE;
741 }
742 RETVAL_TRUE;
743 }
744 /* }}} */
745
746 /* {{{ proto string EventHttpRequest::findHeader(string key, int type);
747 * Finds the value belonging a header.
748 * <parameter>type</parameter> is one of <literal>EventHttpRequest::*_HEADER</literal>
749 * constants.
750 * Returns &null; if header not found.
751 */
752 PHP_METHOD(EventHttpRequest, findHeader)
753 {
754 php_event_http_req_t *http_req;
755 char *key;
756 size_t key_len;
757 struct evkeyvalq *headers;
758 zend_long type;
759 const char *val;
760
761 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
762 &key, &key_len, &type) == FAILURE) {
763 return;
764 }
765
766 _check_http_req_type(type);
767
768 http_req = Z_EVENT_HTTP_REQ_OBJ_P(getThis());
769 _check_http_req_ptr(http_req);
770
771 headers = _get_http_req_headers(http_req, type);
772 PHP_EVENT_ASSERT(headers);
773
774 val = evhttp_find_header(headers, key);
775 if (val == NULL) {
776 RETURN_NULL();
777 }
778
779 RETVAL_STRING(val);
780 }
781 /* }}} */
782
783 /*
784 * Local variables:
785 * tab-width: 4
786 * c-basic-offset: 4
787 * End:
788 * vim600: noet sw=4 ts=4 sts=4 fdm=marker
789 * vim<600: noet sw=4 ts=4 sts=4
790 */
791