From 87db9817d428282792c8146d9c2ae9748ebf6f1e Mon Sep 17 00:00:00 2001
From: Michael Wallner Compose a valid HTTP date regarding RFC 1123 Accepts an optional unix timestamp as parameter. Returns the HTTP date as string. Build an URL. Expexts (part(s) of) an URL as first parameter in form of a string or assoziative array The parts of the second URL will be merged into the first according to the flags argument.http_functions.c
-string http_date([int timestamp])
-
-looking like: "Wed, 22 Dec 2004 11:34:47 GMT"string http_build_url([mixed url[, mixed parts[, int flags = HTTP_URL_REPLACE[, array &new_url]]]])
-
-like parse_url() returns. Accepts an optional second parameter in the same way as the
-first argument. Accepts an optional third integer parameter, which is a bitmask of
-binary or'ed HTTP_URL_* constants. The optional fourth parameter will be filled
-with the results as associative array like parse_url() would return.
-The following flags are recognized: - HTTP_URL_REPLACE: (default) set parts of the second url will replace the parts in the first
- - HTTP_URL_JOIN_PATH: the path of the second url will be merged into the one of the first
- - HTTP_URL_JOIN_QUERY: the two querystrings will be merged recursively
- - HTTP_URL_STRIP_USER: the user part will not appear in the result
- - HTTP_URL_STRIP_PASS: the password part will not appear in the result
- - HTTP_URL_STRIP_AUTH: neither the user nor the password part will appear in the result
- - HTTP_URL_STRIP_PORT: no explicit port will be set in the result
- - HTTP_URL_STRIP_PATH: the path part will not appear in the result
- - HTTP_URL_STRIP_QUERY: no query string will be present in the result
- - HTTP_URL_STRIP_FRAGMENT: no fragment will be present in the result
-
Example:
-
-<?php
// ftp://ftp.example.com/pub/files/current/?a=b&a=c
echo http_build_url("http://user@www.example.com/pub/index.php?a=b#files",
array(
"scheme" => "ftp",
"host" => "ftp.example.com",
"path" => "files/current/",
"query" => "a=c"
),
HTTP_URL_STRIP_AUTH | HTTP_URL_JOIN_PATH | HTTP_URL_JOIN_QUERY | HTTP_URL_STRIP_FRAGMENT
);
?>
-
Opponent to parse_str().
-Expects an array as first argument which represents the parts of the query string to build.
-Accepts a string as optional second parameter containing a top-level prefix to use.
-The optional third parameter should specify an argument separator to use (by default the
-INI setting arg_separator.output will be used, or "&" if neither is set).
Returns the built query as string on success or FALSE on failure.
-This function negotiates the clients preferred language based on its
-Accept-Language HTTP header. The qualifier is recognized and languages
-without qualifier are rated highest. The qualifier will be decreased by
-10% for partial matches (i.e. matching primary language).
Expects an array as parameter containing the supported languages as values.
-If the optional second parameter is supplied, it will be filled with an
-array containing the negotiation results.
Returns the negotiated language or the default language (i.e. first array entry)
-if none match.
Example:
--
-<?php
$langs = array(
'en-US',// default
'fr',
'fr-FR',
'de',
'de-DE',
'de-AT',
'de-CH',
);
include './langs/'. http_negotiate_language($langs, $result) .'.php';
print_r($result);
?>
-
This function negotiates the clients preferred charset based on its
-Accept-Charset HTTP header. The qualifier is recognized and charsets
-without qualifier are rated highest.
Expects an array as parameter containing the supported charsets as values.
-If the optional second parameter is supplied, it will be filled with an
-array containing the negotiation results.
Returns the negotiated charset or the default charset (i.e. first array entry)
-if none match.
Example:
--
-<?php
$charsets = array(
'iso-8859-1', // default
'iso-8859-2',
'iso-8859-15',
'utf-8'
);
$pref = http_negotiate_charset($charsets, $result);
if (strcmp($pref, 'iso-8859-1')) {
iconv_set_encoding('internal_encoding', 'iso-8859-1');
iconv_set_encoding('output_encoding', $pref);
ob_start('ob_iconv_handler');
}
print_r($result);
?>
-
This function negotiates the clients preferred content type based on its
-Accept HTTP header. The qualifier is recognized and content types
-without qualifier are rated highest.
Expects an array as parameter containing the supported content types as values.
-If the optional second parameter is supplied, it will be filled with an
-array containing the negotiation results.
Returns the negotiated content type or the default content type
-(i.e. first array entry) if none match.
Example:
--
-<?php
$ctypes = array('application/xhtml+xml', 'text/html');
http_send_content_type(http_negotiate_content_type($ctypes));
?>
-
Send HTTP status code.
-Expects an HTTP status code as parameter.
-Returns TRUE on success or FALSE on failure.
-Send a "Last-Modified" header with a valid HTTP date.
-Accepts a unix timestamp, converts it to a valid HTTP date and
-sends it as "Last-Modified" HTTP header. If timestamp is
-omitted, the current time will be sent.
Returns TRUE on success or FALSE on failure.
-Send the Content-Type of the sent entity. This is particularly important
-if you use the http_send() API.
Accepts an optional string parameter containing the desired content type
-(primary/secondary).
Returns TRUE on success or FALSE on failure.
-Send the Content-Disposition. The Content-Disposition header is very useful
-if the data actually sent came from a file or something similar, that should
-be "saved" by the client/user (i.e. by browsers "Save as..." popup window).
Expects a string parameter specifying the file name the "Save as..." dialog
-should display. Optionally accepts a bool parameter, which, if set to true
-and the user agent knows how to handle the content type, will probably not
-cause the popup window to be shown.
Returns TRUE on success or FALSE on failure.
-Matches the given unix timestamp against the clients "If-Modified-Since"
-resp. "If-Unmodified-Since" HTTP headers.
Accepts a unix timestamp which should be matched. Optionally accepts an
-additional bool parameter, which if set to true will check the header
-usually used to validate HTTP ranges. If timestamp is omitted, the
-current time will be used.
Returns TRUE if timestamp represents an earlier date than the header,
-else FALSE.
Matches the given ETag against the clients "If-Match" resp.
-"If-None-Match" HTTP headers.
Expects a string parameter containing the ETag to compare. Optionally
-accepts a bool parameter, which, if set to true, will check the header
-usually used to validate HTTP ranges.
Returns TRUE if ETag matches or the header contained the asterisk ("*"),
-else FALSE.
Attempts to cache the sent entity by its last modification date.
-Accepts a unix timestamp as parameter which is handled as follows:
-If timestamp_or_expires is greater than 0, it is handled as timestamp
-and will be sent as date of last modification. If it is 0 or omitted,
-the current time will be sent as Last-Modified date. If it's negative,
-it is handled as expiration time in seconds, which means that if the
-requested last modification date is not between the calculated timespan,
-the Last-Modified header is updated and the actual body will be sent.
Returns FALSE on failure, or *exits* with "304 Not Modified" if the entity is cached.
-A log entry will be written to the cache log if the INI entry
-http.log.cache is set and the cache attempt was successful.
Attempts to cache the sent entity by its ETag, either supplied or generated
-by the hash algorithm specified by the INI setting "http.etag.mode".
If the clients "If-None-Match" header matches the supplied/calculated
-ETag, the body is considered cached on the clients side and
-a "304 Not Modified" status code is issued.
Returns FALSE on failure, or *exits* with "304 Not Modified" if the entity is cached.
-A log entry is written to the cache log if the INI entry
-"http.log.cache" is set and the cache attempt was successful.
For use with ob_start(). Output buffer handler generating an ETag with
-the hash algorithm specified with the INI setting "http.etag.mode".
Sets the throttle delay and send buffer size for use with http_send() API.
-Provides a basic throttling mechanism, which will yield the current process
-resp. thread until the entity has been completely sent, though.
Expects a double parameter specifying the seconds too sleep() after
-each chunk sent. Additionally accepts an optional int parameter
-representing the chunk size in bytes.
Example:
--
-<?php
// ~ 20 kbyte/s
# http_throttle(1, 20000);
# http_throttle(0.5, 10000);
# http_throttle(0.1, 2000);
http_send_file('document.pdf');
?>
-
Redirect to the given url.
-
-The supplied url will be expanded with http_build_url(), the params array will
-be treated with http_build_query() and the session identification will be appended
-if session is true.
The HTTP response code will be set according to status.
-You can use one of the following constants for convenience:
- - HTTP_REDIRECT 302 Found for GET/HEAD, else 303 See Other
- - HTTP_REDIRECT_PERM 301 Moved Permanently
- - HTTP_REDIRECT_FOUND 302 Found
- - HTTP_REDIRECT_POST 303 See Other
- - HTTP_REDIRECT_PROXY 305 Use Proxy
- - HTTP_REDIRECT_TEMP 307 Temporary Redirect
Please see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3
-for which redirect response code to use in which situation.
To be RFC compliant, "Redirecting to URL." will be displayed,
-if the client doesn't redirect immediately, and the request method was
-another one than HEAD.
Returns FALSE on failure, or *exits* on success.
-A log entry will be written to the redirect log, if the INI entry
-"http.log.redirect" is set and the redirect attempt was successful.
Sends raw data with support for (multiple) range requests.
-Returns TRUE on success, or FALSE on failure.
-Sends a file with support for (multiple) range requests.
-Expects a string parameter referencing the file to send.
-Returns TRUE on success, or FALSE on failure.
-Sends an already opened stream with support for (multiple) range requests.
-Expects a resource parameter referencing the stream to read from.
-Returns TRUE on success, or FALSE on failure.
-Decodes a string that was HTTP-chunked encoded.
-Expects a chunked encoded string as parameter.
-Returns the decoded string on success or FALSE on failure.
-Parses (a) http_message(s) into a simple recursive object structure.
-Expects a string parameter containing a single HTTP message or
-several consecutive HTTP messages.
Returns an hierarchical object structure of the parsed messages.
-Example:
--
-<?php
print_r(http_parse_message(http_get(URL, array('redirect' => 3)));
stdClass object
(
[type] => 2
[httpVersion] => 1.1
[responseCode] => 200
[headers] => Array
(
[Content-Length] => 3
[Server] => Apache
)
[body] => Hi!
[parentMessage] => stdClass object
(
[type] => 2
[httpVersion] => 1.1
[responseCode] => 302
[headers] => Array
(
[Content-Length] => 0
[Location] => ...
)
[body] =>
[parentMessage] => ...
)
)
?>
-
Parses HTTP headers into an associative array.
-Expects a string parameter containing HTTP headers.
-Returns an array on success, or FALSE on failure.
-Example:
--
-<?php
$headers = "content-type: text/html; charset=UTF-8\r\n".
"Server: Funky/1.0\r\n".
"Set-Cookie: foo=bar\r\n".
"Set-Cookie: baz=quux\r\n".
"Folded: works\r\n\ttoo\r\n";
print_r(http_parse_headers($headers));
Array
(
[Content-Type] => text/html; chatset=UTF-8
[Server] => Funky/1.0
[Set-Cookie] => Array
(
[0] => foo=bar
[1] => baz=quux
)
[Folded] => works
too
)
?>
-
Parses HTTP cookies like sent in a response into a struct.
-Expects a string as parameter containing the value of a Set-Cookie response header.
-Returns an stdClass olike shown in the example on success or FALSE on failure.
-Example:
--
-<?php
print_r(http_parse_cookie("foo=bar; bar=baz; path=/; domain=example.com; comment=; secure", 0, array("comment")));
stdClass Object
(
[cookies] => Array
(
[foo] => bar
[bar] => baz
)
[extras] => Array
(
[comment] =>
)
[flags] => 16
[expires] => 0
[path] => /
[domain] => example.com
)
?>
-
Parse parameter list.
-Get a list of incoming HTTP headers.
-Returns an associative array of incoming request headers.
-Get the raw request body (e.g. POST or PUT data).
-This function can not be used after http_get_request_body_stream()
-if the request method was another than POST.
Returns the raw request body as string on success or NULL on failure.
-Create a stream to read the raw request body (e.g. POST or PUT data).
-This function can only be used once if the request method was another than POST.
-Returns the raw request body as stream on success or NULL on failure.
-Match an incoming HTTP header.
-Expects two string parameters representing the header name (case-insensitive)
-and the header value that should be compared. The case sensitivity of the
-header value depends on the additional optional bool parameter accepted.
Returns TRUE if header value matches, else FALSE.
-Performs an HTTP GET request on the supplied url.
-The second parameter, if set, is expected to be an associative
-array where the following keys will be recognized:
- redirect: int, whether and how many redirects to follow-
- - unrestrictedauth: bool, whether to continue sending credentials on
- redirects to a different host
- - proxyhost: string, proxy host in "host[:port]" format
- - proxyport: int, use another proxy port as specified in proxyhost
- - proxytype: int, HTTP_PROXY_HTTP, SOCKS4 or SOCKS5
- - proxyauth: string, proxy credentials in "user:pass" format
- - proxyauthtype: int, HTTP_AUTH_BASIC and/or HTTP_AUTH_NTLM
- - httpauth: string, http credentials in "user:pass" format
- - httpauthtype: int, HTTP_AUTH_BASIC, DIGEST and/or NTLM
- - compress: bool, whether to allow gzip/deflate content encoding
- - port: int, use another port as specified in the url
- - referer: string, the referer to send
- - useragent: string, the user agent to send
- (defaults to PECL::HTTP/version (PHP/version)))
- - headers: array, list of custom headers as associative array
- like array("header" => "value")
- - cookies: array, list of cookies as associative array
- like array("cookie" => "value")
- - encodecookies: bool, whether to urlencode the cookies (default: true)
- - cookiestore: string, path to a file where cookies are/will be stored
- - cookiesession: bool, don't load session cookies from cookiestore if TRUE
- - resume: int, byte offset to start the download from;
- if the server supports ranges
- - range: array, array of arrays, each containing two integers,
- specifying the ranges to download if server support is
- given; only recognized if the resume option is empty
- - maxfilesize: int, maximum file size that should be downloaded;
- has no effect, if the size of the requested entity is not known
- - lastmodified: int, timestamp for If-(Un)Modified-Since header
- - etag: string, quoted etag for If-(None-)Match header
- - timeout: int, seconds the request may take
- - connecttimeout: int, seconds the connect may take
- - onprogress: mixed, progress callback
- - interface: string, outgoing network interface (ifname, ip or hostname)
- - portrange: array, 2 integers specifying outgoing portrange to try
- - ssl: array, with the following options:
- cert: string, path to certificate
- certtype: string, type of certificate
- certpasswd: string, password for certificate
- key: string, path to key
- keytype: string, type of key
- keypasswd: string, pasword for key
- engine: string, ssl engine to use
- version: int, ssl version to use
- verifypeer: bool, whether to verify the peer
- verifyhost: bool whether to verify the host
- cipher_list: string, list of allowed ciphers
- cainfo: string
- capath: string
- random_file: string
- egdsocket: string
-
The optional third parameter will be filled with some additional information
-in form of an associative array, if supplied, like the following example:
--
-<?php
array (
'effective_url' => 'http://www.example.com/',
'response_code' => 302,
'connect_code' => 0,
'filetime' => -1,
'total_time' => 0.212348,
'namelookup_time' => 0.038296,
'connect_time' => 0.104144,
'pretransfer_time' => 0.104307,
'starttransfer_time' => 0.212077,
'redirect_time' => 0,
'redirect_count' => 0,
'size_upload' => 0,
'size_download' => 218,
'speed_download' => 1026,
'speed_upload' => 0,
'header_size' => 307,
'request_size' => 103,
'ssl_verifyresult' => 0,
'ssl_engines' =>
array (
0 => 'dynamic',
1 => 'cswift',
2 => 'chil',
3 => 'atalla',
4 => 'nuron',
5 => 'ubsec',
6 => 'aep',
7 => 'sureware',
8 => '4758cca',
),
'content_length_download' => 218,
'content_length_upload' => 0,
'content_type' => 'text/html',
'httpauth_avail' => 0,
'proxyauth_avail' => 0,
'num_connects' => 1,
'os_errno' => 0,
'error' => '',
)
?>
-
Returns the HTTP response(s) as string on success, or FALSE on failure.
-Performs an HTTP HEAD request on the supplied url.
-See http_get() for a full list of available parameters and options.
-Returns the HTTP response as string on success, or FALSE on failure.
-Performs an HTTP POST request on the supplied url.
-Expects a string as second parameter containing the pre-encoded post data.
-See http_get() for a full list of available parameters and options.
-
-Returns the HTTP response(s) as string on success, or FALSE on failure.
Performs an HTTP POST request on the supplied url.
-Expects an associative array as second parameter, which will be
-www-form-urlencoded. See http_get() for a full list of available options.
Returns the HTTP response(s) as string on success, or FALSE on failure.
-Performs an HTTP PUT request on the supplied url.
-Expects the second parameter to be a string referencing the file to upload.
-See http_get() for a full list of available options.
Returns the HTTP response(s) as string on success, or FALSE on failure.
-Performs an HTTP PUT request on the supplied url.
-Expects the second parameter to be a resource referencing an already
-opened stream, from which the data to upload should be read.
-See http_get() for a full list of available options.
Returns the HTTP response(s) as string on success, or FALSE on failure.
-Performs an HTTP PUT request on the supplied url.
-Expects the second parameter to be a string containing the data to upload.
-See http_get() for a full list of available options.
Returns the HTTP response(s) as string on success, or FALSE on failure.
-Performs a custom HTTP request on the supplied url.
-Expects the first parameter to be an integer specifying the request method to use.
-Accepts an optional third string parameter containing the raw request body.
-See http_get() for a full list of available options.
Returns the HTTP response(s) as string on success, or FALSE on failure.
-Generate x-www-form-urlencoded resp. form-data encoded request body.
-Returns encoded string on success, or FALSE on failure.
-Register a custom request method.
-Expects a string parameter containing the request method name to register.
-Returns the ID of the request method on success, or FALSE on failure.
-Unregister a previously registered custom request method.
-Expects either the request method name or ID.
-Returns TRUE on success, or FALSE on failure.
-Check if a request method is registered (or available by default).
-Expects either the request method name or ID as parameter.
-Returns TRUE if the request method is known, else FALSE.
-Get the literal string representation of a standard or registered request method.
-Expects the request method ID as parameter.
-Returns the request method name as string on success, or FALSE on failure.
-Compress data with gzip, zlib AKA deflate or raw deflate encoding.
-Expects the first parameter to be a string containing the data that should
-be encoded.
Returns the encoded string on success, or NULL on failure.
-Decompress data compressed with either gzip, deflate AKA zlib or raw
-deflate encoding.
Expects a string as parameter containing the compressed data.
-Returns the decoded string on success, or NULL on failure.
-For use with ob_start(). The deflate output buffer handler can only be used once.
-It conflicts with ob_gzhandler and zlib.output_compression as well and should
-not be used after ext/mbstrings mb_output_handler and ext/sessions URL-Rewriter (AKA
-session.use_trans_sid).
For use with ob_start(). Same restrictions as with ob_deflatehandler apply.
-Check for feature that require external libraries.
-Accepts an optional in parameter specifying which feature to probe for.
-If the parameter is 0 or omitted, the return value contains a bitmask of
-all supported features that depend on external libraries.
Available features to probe for are:
-
Returns int, whether requested feature is supported, or a bitmask with
-all supported features.
Creates a new HttpDeflateStream object instance.
-Accepts an optional int parameter specifying how to initialize the deflate stream.
-Passes more data through the deflate stream.
-Expects a string parameter containing (a part of) the data to deflate.
-Returns deflated data on success or FALSE on failure.
-Flushes the deflate stream.
-Returns some deflated data as string on success or FALSE on failure.
-Finalizes the deflate stream. The deflate stream can be reused after finalizing.
-Returns the final part of deflated data.
-Creates a new HttpInflateStream object instance.
-Accepts an optional int parameter specifying how to initialize the inflate stream.
-Passes more data through the inflate stream.
-Expects a string parameter containing (a part of) the data to inflate.
-Returns inflated data on success or FALSE on failure.
-Flush the inflate stream.
-Returns some inflated data as string on success or FALSE on failure.
-Finalizes the inflate stream. The inflate stream can be reused after finalizing.
-Returns the final part of inflated data.
-Instantiate a new HttpMessage object.
-Accepts an optional string parameter containing a single or several
-consecutive HTTP messages. The constructed object will actually
-represent the *last* message of the passed string. If there were
-prior messages, those can be accessed by HttpMessage::getParentMessage().
Throws HttpMalformedHeaderException.
-Create an HttpMessage object from a string. Kind of a static constructor.
-Expects a string parameter containing a single or several consecutive
-HTTP messages. Accepts an optional string parameter specifying the class to use.
Returns an HttpMessage object on success or NULL on failure.
-Throws HttpMalformedHeadersException.
-Get the body of the parsed HttpMessage.
-Returns the message body as string.
-Set the body of the HttpMessage.
-NOTE: Don't forget to update any headers accordingly.
Expects a string parameter containing the new body of the message.
-Get message header.
-Returns the header value on success or NULL if the header does not exist.
-Get Message Headers.
-Returns an associative array containing the messages HTTP headers.
-Sets new headers.
-Expects an associative array as parameter containing the new HTTP headers,
-which will replace *all* previous HTTP headers of the message.
Add headers. If append is true, headers with the same name will be separated, else overwritten.
-Expects an associative array as parameter containing the additional HTTP headers
-to add to the messages existing headers. If the optional bool parameter is true,
-and a header with the same name of one to add exists already, this respective
-header will be converted to an array containing both header values, otherwise
-it will be overwritten with the new header value.
Get Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
-Returns the HttpMessage::TYPE.
-Set Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
-Expects an int parameter, the HttpMessage::TYPE.
-Get the Response Code of the Message.
-Returns the HTTP response code if the message is of type
-HttpMessage::TYPE_RESPONSE, else FALSE.
Set the response code of an HTTP Response Message.
-Expects an int parameter with the HTTP response code.
-Returns TRUE on success, or FALSE if the message is not of type
-HttpMessage::TYPE_RESPONSE or the response code is out of range (100-510).
Get the Response Status of the message (i.e. the string following the response code).
-Returns the HTTP response status string if the message is of type
-HttpMessage::TYPE_RESPONSE, else FALSE.
Set the Response Status of the HTTP message (i.e. the string following the response code).
-Expects a string parameter containing the response status text.
-Returns TRUE on success or FALSE if the message is not of type
-HttpMessage::TYPE_RESPONSE.
Get the Request Method of the Message.
-Returns the request method name on success, or FALSE if the message is
-not of type HttpMessage::TYPE_REQUEST.
Set the Request Method of the HTTP Message.
-Expects a string parameter containing the request method name.
-Returns TRUE on success, or FALSE if the message is not of type
-HttpMessage::TYPE_REQUEST or an invalid request method was supplied.
Get the Request URL of the Message.
-Returns the request url as string on success, or FALSE if the message
-is not of type HttpMessage::TYPE_REQUEST.
Set the Request URL of the HTTP Message.
-Expects a string parameters containing the request url.
-Returns TRUE on success, or FALSE if the message is not of type
-HttpMessage::TYPE_REQUEST or supplied URL was empty.
Get the HTTP Protocol Version of the Message.
-Returns the HTTP protocol version as string.
-Set the HTTP Protocol version of the Message.
-Expects a string parameter containing the HTTP protocol version.
-Returns TRUE on success, or FALSE if supplied version is out of range (1.0/1.1).
-Attempts to guess the content type of supplied payload through libmagic.
-Expects a string parameter specifying the magic.mime database to use.
-Additionally accepts an optional int parameter, being flags for libmagic.
Returns the guessed content type on success, or FALSE on failure.
-Throws HttpRuntimeException, HttpInvalidParamException
-if http.only_exceptions is TRUE.
Get parent Message.
-Returns the parent HttpMessage on success, or NULL if there's none.
-Throws HttpRuntimeException.
-Send the Message according to its type as Response or Request.
-This provides limited functionality compared to HttpRequest and HttpResponse.
Returns TRUE on success, or FALSE on failure.
-Get the string representation of the Message.
-Accepts a bool parameter which specifies whether the returned string
-should also contain any parent messages.
Returns the full message as string.
-Creates an object regarding to the type of the message.
-Returns either an HttpRequest or HttpResponse object on success, or NULL on failure.
-Throws HttpRuntimeException, HttpMessageTypeException, HttpHeaderException.
-Implements Countable.
-Returns the number of parent messages + 1.
-Implements Serializable.
-Returns the serialized representation of the HttpMessage.
-Implements Serializable.
-Re-constructs the HttpMessage based upon the serialized string.
-Returns a clone of an HttpMessage object detached from any parent messages.
-Prepends message(s) to the HTTP message.
-Expects an HttpMessage object as parameter.
-Throws HttpInvalidParamException if the message is located within the same message chain.
-Reorders the message chain in reverse order.
-Returns the most parent HttpMessage object.
-Implements Iterator.
-Implements Iterator.
-Implements Iterator.
-Implements Iterator.
-Implements Iterator.
-Creates a new HttpQueryString object instance.
-Operates on and modifies $_GET and $_SERVER['QUERY_STRING'] if global is TRUE.
Returns the string representation.
-Returns the array representation.
-Get (part of) the query string.
-The type parameter is either one of the HttpQueryString::TYPE_* constants or a type abbreviation like
-"b" for bool, "i" for int, "f" for float, "s" for string, "a" for array and "o" for a stdClass object.
Set query string entry/entries. NULL values will unset the variable.
-Copies the query string object and sets provided params at the clone.
-This is basically shorthand for:
--
-<?php
$newQS = new HttpQueryString(false, $oldQS);
$newQS->set($other_params);
?>
-
Get a single instance (differentiates between the global setting).
-Converts the query string from the source encoding ie to the target encoding oe.
-WARNING: Don't use any character set that can contain NUL bytes like UTF-16.
Returns TRUE on success or FALSE on failure.
-Implements Serializable.
-Implements Serializable.
-Implements ArrayAccess.
-Implements ArrayAccess.
-Implements ArrayAccess.
-Implements ArrayAccess.
-Instantiate a new HttpRequest object.
-Accepts a string as optional parameter containing the target request url.
-Additionally accepts an optional int parameter specifying the request method
-to use and an associative array as optional third parameter which will be
-passed to HttpRequest::setOptions().
Throws HttpException.
-Set the request options to use. See http_get() for a full list of available options.
-Accepts an array as optional parameters, which values will overwrite the
-currently set request options. If the parameter is empty or omitted,
-the options of the HttpRequest object will be reset.
Returns TRUE on success, or FALSE on failure.
-Get currently set options.
-Returns an associative array containing currently set options.
-Set SSL options.
-Accepts an associative array as parameter containing any SSL specific options.
-If the parameter is empty or omitted, the SSL options will be reset.
Returns TRUE on success, or FALSE on failure.
-Set additional SSL options.
-Expects an associative array as parameter containing additional SSL specific options.
-Returns TRUE on success, or FALSE on failure.
-Get previously set SSL options.
-Returns an associative array containing any previously set SSL options.
-Add request header name/value pairs.
-Expects an associative array as parameter containing additional header
-name/value pairs.
Returns TRUE on success, or FALSE on failure.
-Set request header name/value pairs.
-Accepts an associative array as parameter containing header name/value pairs.
-If the parameter is empty or omitted, all previously set headers will be unset.
Returns TRUE on success, or FALSE on failure.
-Get previously set request headers.
-Returns an associative array containing all currently set headers.
-Set cookies.
-Accepts an associative array as parameter containing cookie name/value pairs.
-If the parameter is empty or omitted, all previously set cookies will be unset.
Returns TRUE on success, or FALSE on failure.
-Add cookies.
-Expects an associative array as parameter containing any cookie name/value
-pairs to add.
Returns TRUE on success, or FALSE on failure.
-Get previously set cookies.
-Returns an associative array containing any previously set cookies.
-Enable automatic sending of received cookies.
-Note that cuutomly set cookies will be sent anyway.
Reset all automatically received/sent cookies.
-Note that customly set cookies are not affected.
Accepts an optional bool parameter specifying
-whether only session cookies should be reset
-(needs libcurl >= v7.15.4, else libcurl >= v7.14.1).
Returns TRUE on success, or FALSE on failure.
-Set the request URL.
-Expects a string as parameter specifying the request url.
-Returns TRUE on success, or FALSE on failure.
-Get the previously set request URL.
-Returns the currently set request url as string.
-Set the request method.
-Expects an int as parameter specifying the request method to use.
-In PHP 5.1+ HttpRequest::METH_*, otherwise the HTTP_METH_* constants can be used.
Returns TRUE on success, or FALSE on failure.
-Get the previously set request method.
-Returns the currently set request method.
-Set the content type the post request should have.
-Expects a string as parameters containing the content type of the request
-(primary/secondary).
Returns TRUE on success, or FALSE if the content type does not seem to
-contain a primary and a secondary part.
Get the previously content type.
-Returns the previously set content type as string.
-Set the URL query parameters to use, overwriting previously set query parameters.
-Affects any request types.
Accepts a string or associative array parameter containing the pre-encoded
-query string or to be encoded query fields. If the parameter is empty or
-omitted, the query data will be unset.
Returns TRUE on success, or FALSE on failure.
-Get the current query data in form of an urlencoded query string.
-Returns a string containing the urlencoded query.
-Add parameters to the query parameter list, leaving previously set unchanged.
-Affects any request type.
Expects an associative array as parameter containing the query fields to add.
-Returns TRUE on success, or FALSE on failure.
-Adds POST data entries, leaving previously set unchanged, unless a
-post entry with the same name already exists.
-Affects only POST and custom requests.
Expects an associative array as parameter containing the post fields.
-Returns TRUE on success, or FALSE on failure.
-Set the POST data entries, overwriting previously set POST data.
-Affects only POST and custom requests.
Accepts an associative array as parameter containing the post fields.
-If the parameter is empty or omitted, the post data will be unset.
Returns TRUE on success, or FALSE on failure.
-Get previously set POST data.
-Returns the currently set post fields as associative array.
-Set raw post data to send, overwriting previously set raw post data. Don't
-forget to specify a content type. Affects only POST and custom requests.
-Only either post fields or raw post data can be used for each request.
-Raw post data has higher precedence and will be used even if post fields
-are set.
Accepts a string as parameter containing the *raw* post data.
-Returns TRUE on success, or FALSE on failure.
-Add raw post data, leaving previously set raw post data unchanged.
-Affects only POST and custom requests.
Expects a string as parameter containing the raw post data to concatenate.
-Returns TRUE on success, or FALSE on failure.
-Get previously set raw post data.
-Returns a string containing the currently set raw post data.
-Add a file to the POST request, leaving previously set files unchanged.
-Affects only POST and custom requests. Cannot be used with raw post data.
Expects a string parameter containing the form element name, and a string
-paremeter containing the path to the file which should be uploaded.
-Additionally accepts an optional string parameter which should contain
-the content type of the file.
Returns TRUE on success, or FALSE if the content type seems not to contain a
-primary and a secondary content type part.
Set files to post, overwriting previously set post files.
-Affects only POST and requests. Cannot be used with raw post data.
Accepts an array containing the files to post. Each entry should be an
-associative array with "name", "file" and "type" keys. If the parameter
-is empty or omitted the post files will be unset.
Returns TRUE on success, or FALSE on failure.
-Get all previously added POST files.
-Returns an array containing currently set post files.
-Set file to put. Affects only PUT requests.
-Accepts a string as parameter referencing the path to file.
-If the parameter is empty or omitted the put file will be unset.
Returns TRUE on success, or FALSE on failure.
-Get previously set put file.
-Returns a string containing the path to the currently set put file.
-Set PUT data to send, overwriting previously set PUT data.
-Affects only PUT requests.
-Only either PUT data or PUT file can be used for each request.
-PUT data has higher precedence and will be used even if a PUT
-file is set.
Accepts a string as parameter containing the data to upload.
-Returns TRUE on success, or FALSE on failure.
-Add PUT data, leaving previously set PUT data unchanged.
-Affects only PUT requests.
Expects a string as parameter containing the data to concatenate.
-Returns TRUE on success, or FALSE on failure.
-Get previously set PUT data.
-Returns a string containing the currently set raw post data.
-Get all response data after the request has been sent.
-Returns an associative array with the key "headers" containing an associative
-array holding all response headers, as well as the key "body" containing a
-string with the response body.
If redirects were allowed and several responses were received, the data
-references the last received response.
Get response header(s) after the request has been sent.
-Accepts an string as optional parameter specifying a certain header to read.
-If the parameter is empty or omitted all response headers will be returned.
Returns either a string with the value of the header matching name if requested,
-FALSE on failure, or an associative array containing all response headers.
If redirects were allowed and several responses were received, the data
-references the last received response.
Get response cookie(s) after the request has been sent.
-Returns an array of stdClass objects like http_parse_cookie would return.
-If redirects were allowed and several responses were received, the data
-references the last received response.
Get the response body after the request has been sent.
-Returns a string containing the response body.
-If redirects were allowed and several responses were received, the data
-references the last received response.
Get the response code after the request has been sent.
-Returns an int representing the response code.
-If redirects were allowed and several responses were received, the data
-references the last received response.
Get the response status (i.e. the string after the response code) after the message has been sent.
-Returns a string containing the response status text.
-Get response info after the request has been sent.
-See http_get() for a full list of returned info.
Accepts a string as optional parameter specifying the info to read.
-If the parameter is empty or omitted, an associative array containing
-all available info will be returned.
Returns either a scalar containing the value of the info matching name if
-requested, FALSE on failure, or an associative array containing all
-available info.
If redirects were allowed and several responses were received, the data
-references the last received response.
Get the full response as HttpMessage object after the request has been sent.
-Returns an HttpMessage object of the response.
-If redirects were allowed and several responses were received, the data
-references the last received response. Use HttpMessage::getParentMessage()
-to access the data of previously received responses within this request
-cycle.
Throws HttpException, HttpRuntimeException.
-Get sent HTTP message.
-Returns an HttpMessage object representing the sent request.
-If redirects were allowed and several responses were received, the data
-references the last received response. Use HttpMessage::getParentMessage()
-to access the data of previously sent requests within this request
-cycle.
Note that the internal request message is immutable, that means that the
-request message received through HttpRequest::getRequestMessage() will
-always look the same for the same request, regardless of any changes you
-may have made to the returned object.
Throws HttpMalformedHeadersException, HttpEncodingException.
-Get sent HTTP message.
-Returns an HttpMessage in a form of a string
-Get the entire HTTP response.
-Returns the complete web server response, including the headers in a form of a string.
-Get all sent requests and received responses as an HttpMessage object.
-If you want to record history, set the instance variable
-HttpRequest::$recordHistory to TRUE.
Returns an HttpMessage object representing the complete request/response
-history.
The object references the last received response, use HttpMessage::getParentMessage()
-to access the data of previously sent requests and received responses.
Throws HttpRuntimeException.
-Clear the history.
-Send the HTTP request.
-Returns the received response as HttpMessage object.
-NOTE: While an exception may be thrown, the transfer could have succeeded
-at least partially, so you might want to check the return values of various
-HttpRequest::getResponse*() methods.
Throws HttpRuntimeException, HttpRequestException,
-HttpMalformedHeaderException, HttpEncodingException.
GET example:
--
-<?php
$r = new HttpRequest('http://example.com/feed.rss', HttpRequest::METH_GET);
$r->setOptions(array('lastmodified' => filemtime('local.rss')));
$r->addQueryData(array('category' => 3));
try {
$r->send();
if ($r->getResponseCode() == 200) {
file_put_contents('local.rss', $r->getResponseBody());
}
} catch (HttpException $ex) {
echo $ex;
}
?>
-
POST example:
--
-<?php
$r = new HttpRequest('http://example.com/form.php', HttpRequest::METH_POST);
$r->setOptions(array('cookies' => array('lang' => 'de')));
$r->addPostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));
$r->addPostFile('image', 'profile.jpg', 'image/jpeg');
try {
echo $r->send()->getBody();
} catch (HttpException $ex) {
echo $ex;
}
?>
-
Instantiate a new HttpRequestPool object. An HttpRequestPool is
-able to send several HttpRequests in parallel.
WARNING: Don't attach/detach HttpRequest objects to the HttpRequestPool
-object while you're using the implemented Iterator interface.
Accepts virtual infinite optional parameters each referencing an
-HttpRequest object.
Throws HttpRequestPoolException (HttpRequestException, HttpInvalidParamException).
-Example:
--
-<?php
try {
$pool = new HttpRequestPool(
new HttpRequest('http://www.google.com/', HttpRequest::METH_HEAD),
new HttpRequest('http://www.php.net/', HttpRequest::METH_HEAD)
);
$pool->send();
foreach($pool as $request) {
printf("%s is %s (%d)\n",
$request->getUrl(),
$request->getResponseCode() ? 'alive' : 'not alive',
$request->getResponseCode()
);
}
} catch (HttpException $e) {
echo $e;
}
?>
-
Clean up HttpRequestPool object.
-Detach all attached HttpRequest objects.
-Attach an HttpRequest object to this HttpRequestPool.
-WARNING: set all options prior attaching!
Expects the parameter to be an HttpRequest object not already attached to
-antother HttpRequestPool object.
Returns TRUE on success, or FALSE on failure.
-Throws HttpInvalidParamException, HttpRequestException,
-HttpRequestPoolException, HttpEncodingException.
Detach an HttpRequest object from this HttpRequestPool.
-Expects the parameter to be an HttpRequest object attached to this
-HttpRequestPool object.
Returns TRUE on success, or FALSE on failure.
-Throws HttpInvalidParamException, HttpRequestPoolException.
-Send all attached HttpRequest objects in parallel.
-Returns TRUE on success, or FALSE on failure.
-Throws HttpRequestPoolException (HttpSocketException, HttpRequestException, HttpMalformedHeaderException).
-Returns TRUE until each request has finished its transaction.
-Usage:
--
-<?php
class MyPool extends HttpRequestPool
{
public function send()
{
while ($this->socketPerform()) {
if (!$this->socketSelect()) {
throw new HttpSocketExcpetion;
}
}
}
protected final function socketPerform()
{
$result = parent::socketPerform();
foreach ($this->getFinishedRequests() as $r) {
$this->detach($r);
// handle response of finished request
}
return $result;
}
}
?>
-
See HttpRequestPool::socketPerform().
-Returns TRUE on success, or FALSE on failure.
-Implements Iterator::valid().
-Implements Iterator::current().
-Implements Iterator::key().
-Implements Iterator::next().
-Implements Iterator::rewind().
-Implements Countable.
-Returns the number of attached HttpRequest objects.
-Get attached HttpRequest objects.
-Returns an array containing all currently attached HttpRequest objects.
-Get attached HttpRequest objects that already have finished their work.
-Returns an array containing all attached HttpRequest objects that
-already have finished their work.
Send an HTTP header.
-Expects a string parameter containing the name of the header and a mixed
-parameter containing the value of the header, which will be converted to
-a string. Additionally accepts an optional boolean parameter, which
-specifies whether an existing header should be replaced. If the second
-parameter is unset no header with this name will be sent.
Returns TRUE on success, or FALSE on failure.
-Throws HttpHeaderException if http.only_exceptions is TRUE.
-Get header(s) about to be sent.
-Accepts a string as optional parameter which specifies the name of the
-header to read. If the parameter is empty or omitted, an associative array
-with all headers will be returned.
NOTE: In Apache2 this only works for PHP-5.1.3 and greater.
-Returns either a string containing the value of the header matching name,
-FALSE on failure, or an associative array with all headers.
Whether it should be attempted to cache the entity.
-This will result in necessary caching headers and checks of clients
-"If-Modified-Since" and "If-None-Match" headers. If one of those headers
-matches a "304 Not Modified" status code will be issued.
NOTE: If you're using sessions, be sure that you set session.cache_limiter
-to something more appropriate than "no-cache"!
Expects a boolean as parameter specifying whether caching should be attempted.
-Returns TRUE on success, or FALSE on failure.
-Get current caching setting.
-Returns TRUE if caching should be attempted, else FALSE.
-Enable on-thy-fly gzipping of the sent entity.
-Expects a boolean as parameter indicating if GZip compression should be enabled.
-Returns TRUE on success, or FALSE on failure.
-Get current gzipping setting.
-Returns TRUE if GZip compression is enabled, else FALSE.
-Set a custom cache-control header, usually being "private" or "public";
-The max_age parameter controls how long the cache entry is valid on the client side.
Expects a string parameter containing the primary cache control setting.
-Additionally accepts an int parameter specifying the max-age setting.
-Accepts an optional third bool parameter indicating whether the cache
-must be revalidated every request.
Returns TRUE on success, or FALSE if control does not match one of
-"public" , "private" or "no-cache".
Throws HttpInvalidParamException if http.only_exceptions is TRUE.
-Get current Cache-Control header setting.
-Returns the current cache control setting as a string like sent in a header.
-Set the content-type of the sent entity.
-Expects a string as parameter specifying the content type of the sent entity.
-Returns TRUE on success, or FALSE if the content type does not seem to
-contain a primary and secondary content type part.
Throws HttpInvalidParamException if http.only_exceptions is TRUE.
-Get current Content-Type header setting.
-Returns the currently set content type as string.
-Attempts to guess the content type of supplied payload through libmagic.
-If the attempt is successful, the guessed content type will automatically
-be set as response content type.
Expects a string parameter specifying the magic.mime database to use.
-Additionally accepts an optional int parameter, being flags for libmagic.
Returns the guessed content type on success, or FALSE on failure.
-Throws HttpRuntimeException, HttpInvalidParamException
-if http.only_exceptions is TRUE.
Set the Content-Disposition. The Content-Disposition header is very useful
-if the data actually sent came from a file or something similar, that should
-be "saved" by the client/user (i.e. by browsers "Save as..." popup window).
Expects a string parameter specifying the file name the "Save as..." dialog
-should display. Optionally accepts a bool parameter, which, if set to true
-and the user agent knows how to handle the content type, will probably not
-cause the popup window to be shown.
Returns TRUE on success or FALSE on failure.
-Get current Content-Disposition setting.
-Returns the current content disposition as string like sent in a header.
-Set a custom ETag. Use this only if you know what you're doing.
-Expects an unquoted string as parameter containing the ETag.
-Returns TRUE on success, or FALSE on failure.
-Get calculated or previously set custom ETag.
-Returns the calculated or previously set ETag as unquoted string.
-Set a custom Last-Modified date.
-Expects an unix timestamp as parameter representing the last modification
-time of the sent entity.
Returns TRUE on success, or FALSE on failure.
-Get calculated or previously set custom Last-Modified date.
-Returns the calculated or previously set unix timestamp.
-Sets the throttle delay for use with HttpResponse::setBufferSize().
-Provides a basic throttling mechanism, which will yield the current process
-resp. thread until the entity has been completely sent, though.
Note: This doesn't really work with the FastCGI SAPI.
-Expects a double parameter specifying the seconds too sleep() after
-each chunk sent.
Returns TRUE on success, or FALSE on failure.
-Get the current throttle delay.
-Returns a double representing the throttle delay in seconds.
-Sets the send buffer size for use with HttpResponse::setThrottleDelay().
-Provides a basic throttling mechanism, which will yield the current process
-resp. thread until the entity has been completely sent, though.
Note: This doesn't really work with the FastCGI SAPI.
-Expects an int parameter representing the chunk size in bytes.
-Returns TRUE on success, or FALSE on failure.
-Get current buffer size.
-Returns an int representing the current buffer size in bytes.
-Set the data to be sent.
-Expects one parameter, which will be converted to a string and contains
-the data to send.
Returns TRUE on success, or FALSE on failure.
-Get the previously set data to be sent.
-Returns a string containing the previously set data to send.
-Set the resource to be sent.
-Expects a resource parameter referencing an already opened stream from
-which the data to send will be read.
Returns TRUE on success, or FALSE on failure.
-Get the previously set resource to be sent.
-Returns the previously set resource.
-Set the file to be sent.
-Expects a string as parameter, specifying the path to the file to send.
-Returns TRUE on success, or FALSE on failure.
-Get the previously set file to be sent.
-Returns the previously set path to the file to send as string.
-Finally send the entity.
-Accepts an optional boolean parameter, specifying whether the output
-buffers should be discarded prior sending. A successful caching attempt
-will cause a script termination, and write a log entry if the INI setting
-http.cache_log is set.
Returns TRUE on success, or FALSE on failure.
-Throws HttpHeaderException, HttpResponseException if http.only_exceptions is TRUE.
-Example:
--
-<?php
HttpResponse::setCache(true);
HttpResponse::setContentType('application/pdf');
HttpResponse::setContentDisposition("$user.pdf", false);
HttpResponse::setFile('sheet.pdf');
HttpResponse::send();
?>
-
Capture script output.
-Example:
--
-<?php
HttpResponse::setCache(true);
HttpResponse::capture();
// script follows
?>
-
Generated at: Fri, 07 Jul 2006 21:23:59 +0200
- - - diff --git a/docs/http.ini b/docs/http.ini deleted file mode 100644 index a32ad46..0000000 --- a/docs/http.ini +++ /dev/null @@ -1,61 +0,0 @@ -; example INI file for pecl/http -; $Id$ - -[http] -; enable if you want to transform all errors to exceptions (PHP >= 5 only) -;http.only_exceptions = 1 - -; disable if you don't want php to exit in case of redirects and cache hits; -; a "NULL" output handler will be started instead, which discards all output -;http.force_exit = 0 - -; disable if you don't want 404 Not found status messages being sent, -; if a file attempted to be sent with http_send_file() etc. cannot be found -;http.send.not_found_404 = 0 - -; the hashing algorithm with wich ETags are generated (MD5, SHA1, CRC32B); -; if ext/hash is available, this can be set to any hash algorithm ext/hash supports -; MD5 is the default and fallback algorithm -;http.etag.mode = "MD5" - -; allowed request methods -; by default PHP ignores unkown request methods -; PHP will exit with a response status of 405 and an Allow header -; if it encounters a request method not contained in the specified list -;http.request.methods.allowed = "HEAD, GET, POST" - -; custom request methods -;http.request.methods.custom = "KICK, BANN" - -; log file for positive cache hits -;http.log.cache = - -; log file for redirects -;http.log.redirect = - -; log file for responses with http_send_file() etc. where the file's not been found -;http.log.not_found = - -; log file for requests with an unallowed request method -;http.log.allowed_methods = - -; composite log file (i.e. log all messages to this file) -;http.log.composite = - -; automatically deflate content if requested/supported by client -;http.send.deflate.start_auto = 1 -;http.send.deflate.start_flags = HTTP_DEFLATE_LEVEL_DEF - -; automatically inflate sent content -;http.send.inflate.start_auto = 0 -;http.send.inflate.start_flags = - -; global HttpRequestDataShare settings -;http.request.datashare.cookie = 0 -;http.request.datashare.dns = 1 - -; limit of idle persistent handles per provider -;http.persistent.handles.limit = -1 - -; default ident of persistent handles -;http.persistent.handles.ident = "GLOBAL" diff --git a/funcsummary.php b/funcsummary.php deleted file mode 100644 index 27b602d..0000000 --- a/funcsummary.php +++ /dev/null @@ -1,171 +0,0 @@ -#! /usr/bin/php -%s\n", highlight_string($m[1], true)); -} -function mf($f, &$m) -{ - return preg_match_all( - '/\/\* *\{\{\{ *proto (.*?)(\n|$)(.*?)PHP_(?:FUNCTION|METHOD)\((.*?)\)/s', - file_get_contents($f), $m); -} -function ff($t) -{ - $t = preg_replace('/^ \* /m', '', trim($t, "*/ \n")); - $t = preg_replace_callback('/(\<\?php.*?\?\>)/s', 'hl', $t); - $t = str_replace("", nl2br(preg_replace('/\n *\* */', "\n", $t)));
- $t = preg_replace('/(\
\n)+\
(\
\n)+/', '', $t); - $t = preg_replace('/(\
\n)+\<\/pre\>(\
\n)+/', '', $t); - $t = str_replace("
\n", "", $t); - return sprintf('%s
', ltrim($t, ' *')); -} -function e($s) -{ - $a = func_get_args(); - array_unshift($a, STDERR); - call_user_func_array('fprintf', $a); -} - -$preface = <<<_PREFACE - - -Function Summary of ext/%s - - - -_PREFACE; - -$footer = <<<_FOOTER -Generated at: %s
- - - -_FOOTER; - -if ($_SERVER['argc'] < 2) { - die("Usage: {$_SERVER['argv'][0]}[ ...]\n"); -} - -$TOC = array(); - -printf($preface, basename(getcwd())); - -$seen = array(); -foreach (array_slice($_SERVER['argv'], 1) as $fp) { - foreach (glob($fp) as $f) { - if (isset($seen[$f])) { - continue; - } else { - $seen[$f] = true; - } - if (mf($f, $m)) { - $c = null; - e("\nAnalyzing %s\n", basename($f)); - printf(" %s
\n", basename($f), basename($f)); - foreach ($m[1] as $i => $p) { - e("Documenting $p\n"); - if ($o = preg_match('/^(.*), (.*)$/', $m[4][$i], $n)) { - if ($n[1] != $c) { - $c = $n[1]; - printf("%s
\n", $n[1], $n[1]); - } - $TOC[basename($f)][$n[1]][$n[2]] = $n[1].'::'.$n[2].'()'; - printf("%s \n", 3, $n[1].'_'.$n[2], $p, 3); - } else { - $TOC[basename($f)][$m[4][$i]] = $m[4][$i].'()'; - printf("%s \n", 2, $m[4][$i], $p, 2); - } - print ff($m[3][$i]) ."\n"; - } - print "
\n"; - } - } -} -printf("Table of Contents\n\n\n"); - -printf($footer, date('r')); -e("\nDone\n"); -?> - diff --git a/scripts/gen_curlinfo.php b/gen_curlinfo.php similarity index 70% rename from scripts/gen_curlinfo.php rename to gen_curlinfo.php index b69c96c..fea14bb 100644 --- a/scripts/gen_curlinfo.php +++ b/gen_curlinfo.php @@ -1,6 +1,6 @@ #!/usr/bin/env php 'HTTP_CURL_VERSION(7,14,1)', - 'PRIMARY_IP' => 'HTTP_CURL_VERSION(7,19,0)', - 'APPCONNECT_TIME' => 'HTTP_CURL_VERSION(7,19,0)', - 'REDIRECT_URL' => 'HTTP_CURL_VERSION(7,18,2)', - 'CONDITION_UNMET' => 'HTTP_CURL_VERSION(7,19,4)', - 'PRIMARY_PORT' => 'HTTP_CURL_VERSION(7,21,0)', - 'LOCAL_PORT' => 'HTTP_CURL_VERSION(7,21,0)', - 'LOCAL_IP' => 'HTTP_CURL_VERSION(7,21,0)', + 'PRIMARY_IP' => 'PHP_HTTP_CURL_VERSION(7,19,0)', + 'APPCONNECT_TIME' => 'PHP_HTTP_CURL_VERSION(7,19,0)', + 'CONDITION_UNMET' => 'PHP_HTTP_CURL_VERSION(7,19,4)', + 'PRIMARY_PORT' => 'PHP_HTTP_CURL_VERSION(7,21,0)', + 'LOCAL_PORT' => 'PHP_HTTP_CURL_VERSION(7,21,0)', + 'LOCAL_IP' => 'PHP_HTTP_CURL_VERSION(7,21,0)', ); $exclude = array( 'PRIVATE', 'LASTSOCKET', 'FTP_ENTRY_PATH', 'CERTINFO', @@ -53,22 +51,22 @@ $translate = array( $templates = array( 'STRING' => -' if (CURLE_OK == curl_easy_getinfo(request->ch, %s, &c)) { +' if (CURLE_OK == curl_easy_getinfo(ch, %s, &c)) { add_assoc_string_ex(&array, "%s", sizeof("%2$s"), c ? c : "", 1); } ', 'DOUBLE' => -' if (CURLE_OK == curl_easy_getinfo(request->ch, %s, &d)) { +' if (CURLE_OK == curl_easy_getinfo(ch, %s, &d)) { add_assoc_double_ex(&array, "%s", sizeof("%2$s"), d); } ', 'LONG' => -' if (CURLE_OK == curl_easy_getinfo(request->ch, %s, &l)) { +' if (CURLE_OK == curl_easy_getinfo(ch, %s, &l)) { add_assoc_long_ex(&array, "%s", sizeof("%2$s"), l); } ', 'SLIST' => -' if (CURLE_OK == curl_easy_getinfo(request->ch, %s, &s)) { +' if (CURLE_OK == curl_easy_getinfo(ch, %s, &s)) { MAKE_STD_ZVAL(subarray); array_init(subarray); for (p = s; p; p = p->next) { @@ -93,8 +91,8 @@ foreach ($infos as $info) { if (isset($ifdefs[$short])) printf("#endif\n"); } -file_put_contents("http_request_info.c", - preg_replace('/(\/\* BEGIN \*\/\n).*(\/\* END \*\/)/s', '$1'. ob_get_contents() .'$2', - file_get_contents("http_request_info.c"))); +file_put_contents("php_http_curl_client.c", + preg_replace('/(\/\* BEGIN::CURLINFO \*\/\n).*(\n\s*\/\* END::CURLINFO \*\/)/s', '$1'. ob_get_contents() .'$2', + file_get_contents("php_http_curl_client.c"))); ?> diff --git a/http.c b/http.c deleted file mode 100644 index 76629d3..0000000 --- a/http.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner| - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#define HTTP_WANT_CURL -#define HTTP_WANT_EVENT -#define HTTP_WANT_ZLIB -#define HTTP_WANT_MAGIC -#include "php_http.h" - -#include "php_ini.h" -#include "ext/standard/info.h" -#include "zend_extensions.h" - -#include "php_http_api.h" -#include "php_http_cache_api.h" -#include "php_http_cookie_api.h" -#include "php_http_encoding_api.h" -#include "php_http_filter_api.h" -#include "php_http_message_api.h" -#include "php_http_persistent_handle_api.h" -#include "php_http_request_api.h" -#include "php_http_request_datashare_api.h" -#include "php_http_request_method_api.h" -#include "php_http_request_pool_api.h" -#include "php_http_send_api.h" -#include "php_http_url_api.h" - -#include "php_http_deflatestream_object.h" -#include "php_http_exception_object.h" -#include "php_http_inflatestream_object.h" -#include "php_http_message_object.h" -#include "php_http_querystring_object.h" -#include "php_http_request_object.h" -#include "php_http_requestdatashare_object.h" -#include "php_http_requestpool_object.h" -#include "php_http_response_object.h" -#include "php_http_util_object.h" - -ZEND_DECLARE_MODULE_GLOBALS(http); -HTTP_DECLARE_ARG_PASS_INFO(); - -#ifdef COMPILE_DL_HTTP -ZEND_GET_MODULE(http) -#endif - -/* {{{ http_functions[] */ -zend_function_entry http_functions[] = { - PHP_FE(http_date, NULL) - PHP_FE(http_build_url, http_arg_pass_ref_4) - PHP_FE(http_build_str, NULL) -#ifndef ZEND_ENGINE_2 - PHP_FALIAS(http_build_query, http_build_str, NULL) -#endif - PHP_FE(http_negotiate_language, http_arg_pass_ref_2) - PHP_FE(http_negotiate_charset, http_arg_pass_ref_2) - PHP_FE(http_negotiate_content_type, http_arg_pass_ref_2) - PHP_FE(http_negotiate, http_arg_pass_ref_3) - PHP_FE(http_redirect, NULL) - PHP_FE(http_throttle, NULL) - PHP_FE(http_send_status, NULL) - PHP_FE(http_send_last_modified, NULL) - PHP_FE(http_send_content_type, NULL) - PHP_FE(http_send_content_disposition, NULL) - PHP_FE(http_match_modified, NULL) - PHP_FE(http_match_etag, NULL) - PHP_FE(http_cache_last_modified, NULL) - PHP_FE(http_cache_etag, NULL) - PHP_FE(http_send_data, NULL) - PHP_FE(http_send_file, NULL) - PHP_FE(http_send_stream, NULL) - PHP_FE(http_chunked_decode, NULL) - PHP_FE(http_parse_message, NULL) - PHP_FE(http_parse_headers, NULL) - PHP_FE(http_parse_cookie, NULL) - PHP_FE(http_build_cookie, NULL) - PHP_FE(http_parse_params, NULL) - PHP_FE(http_get_request_headers, NULL) - PHP_FE(http_get_request_body, NULL) - PHP_FE(http_get_request_body_stream, NULL) - PHP_FE(http_match_request_header, NULL) - PHP_FE(http_persistent_handles_count, NULL) - PHP_FE(http_persistent_handles_clean, NULL) - PHP_FE(http_persistent_handles_ident, NULL) -#ifdef HTTP_HAVE_CURL - PHP_FE(http_get, http_arg_pass_ref_3) - PHP_FE(http_head, http_arg_pass_ref_3) - PHP_FE(http_post_data, http_arg_pass_ref_4) - PHP_FE(http_post_fields, http_arg_pass_ref_5) - PHP_FE(http_put_data, http_arg_pass_ref_4) - PHP_FE(http_put_file, http_arg_pass_ref_4) - PHP_FE(http_put_stream, http_arg_pass_ref_4) - PHP_FE(http_request, http_arg_pass_ref_5) - PHP_FE(http_request_body_encode, NULL) -#endif - PHP_FE(http_request_method_register, NULL) - PHP_FE(http_request_method_unregister, NULL) - PHP_FE(http_request_method_exists, NULL) - PHP_FE(http_request_method_name, NULL) - PHP_FE(ob_etaghandler, NULL) -#ifdef HTTP_HAVE_ZLIB - PHP_FE(http_deflate, NULL) - PHP_FE(http_inflate, NULL) - PHP_FE(ob_deflatehandler, NULL) - PHP_FE(ob_inflatehandler, NULL) -#endif - PHP_FE(http_support, NULL) - - EMPTY_FUNCTION_ENTRY -}; -/* }}} */ - -PHP_MINIT_FUNCTION(http); -PHP_MSHUTDOWN_FUNCTION(http); -PHP_RINIT_FUNCTION(http); -PHP_RSHUTDOWN_FUNCTION(http); -PHP_MINFO_FUNCTION(http); - -/* {{{ http_module_dep */ -#if ZEND_EXTENSION_API_NO >= 220050617 -static zend_module_dep http_module_deps[] = { -# ifdef HTTP_HAVE_SPL - ZEND_MOD_REQUIRED("spl") -# endif -# ifdef HTTP_HAVE_HASH - ZEND_MOD_REQUIRED("hash") -# endif -# ifdef HTTP_HAVE_SESSION - ZEND_MOD_REQUIRED("session") -# endif -# ifdef HTTP_HAVE_ICONV - ZEND_MOD_REQUIRED("iconv") -# endif -# ifdef HTTP_HAVE_EVENT - ZEND_MOD_CONFLICTS("event") -#endif - {NULL, NULL, NULL, 0} -}; -#endif -/* }}} */ - -/* {{{ http_module_entry */ -zend_module_entry http_module_entry = { -#if ZEND_EXTENSION_API_NO >= 220050617 - STANDARD_MODULE_HEADER_EX, NULL, - http_module_deps, -#else - STANDARD_MODULE_HEADER, -#endif - "http", - http_functions, - PHP_MINIT(http), - PHP_MSHUTDOWN(http), - PHP_RINIT(http), - PHP_RSHUTDOWN(http), - PHP_MINFO(http), - PHP_HTTP_VERSION, - STANDARD_MODULE_PROPERTIES -}; -/* }}} */ - -int http_module_number; - -/* {{{ http_globals */ -static void http_globals_init_once(zend_http_globals *G) -{ - memset(G, 0, sizeof(zend_http_globals)); -} - -#define http_globals_init(g) _http_globals_init((g) TSRMLS_CC) -static inline void _http_globals_init(zend_http_globals *G TSRMLS_DC) -{ -#ifdef HTTP_HAVE_SAPI_RTIME - G->request.time = sapi_get_request_time(TSRMLS_C); -#else - G->request.time = time(NULL); -#endif - G->send.buffer_size = 0; - G->read_post_data = 0; -} - -#define http_globals_free(g) _http_globals_free((g) TSRMLS_CC) -static inline void _http_globals_free(zend_http_globals *G TSRMLS_DC) -{ - if (G->request.headers) { - zend_hash_destroy(G->request.headers); - FREE_HASHTABLE(G->request.headers); - G->request.headers = NULL; - } - STR_SET(G->send.content_type, NULL); - STR_SET(G->send.unquoted_etag, NULL); - if (G->server_var) { - zval_ptr_dtor(&G->server_var); - G->server_var = NULL; - } -} - -#if defined(ZTS) && defined(PHP_DEBUG) -#if ZTS && PHP_DEBUG -zend_http_globals *http_globals(void) -{ - TSRMLS_FETCH(); - return HTTP_G; -} -#endif -#endif -/* }}} */ - -/* {{{ static inline void http_check_allowed_methods(char *) */ -#define http_check_allowed_methods(m) _http_check_allowed_methods((m) TSRMLS_CC) -static inline void _http_check_allowed_methods(const char *methods TSRMLS_DC) -{ - if (*methods && SG(request_info).request_method) { - if (SUCCESS != http_check_method_ex(SG(request_info).request_method, methods)) { - char *header; - spprintf(&header, 0, "Allow: %s", methods); - http_exit(405, header); - } - } -} -/* }}} */ - -/* {{{ PHP_INI */ -PHP_INI_MH(http_update_allowed_methods) -{ - if (*new_value) { - http_check_allowed_methods(new_value); - } - return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); -} -PHP_INI_MH(http_update_persistent_handle_ident) -{ - HTTP_G->persistent.handles.ident.h = zend_hash_func(new_value, HTTP_G->persistent.handles.ident.l = new_value_length+1); - return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); -} - -#ifndef ZEND_ENGINE_2 -# define OnUpdateLong OnUpdateInt -#endif - -PHP_INI_BEGIN() - HTTP_PHP_INI_ENTRY("http.etag.mode", "MD5", PHP_INI_ALL, OnUpdateString, etag.mode) - HTTP_PHP_INI_ENTRY("http.log.cache", "", PHP_INI_ALL, OnUpdateString, log.cache) - HTTP_PHP_INI_ENTRY("http.log.redirect", "", PHP_INI_ALL, OnUpdateString, log.redirect) - HTTP_PHP_INI_ENTRY("http.log.not_found", "", PHP_INI_ALL, OnUpdateString, log.not_found) - HTTP_PHP_INI_ENTRY("http.log.allowed_methods", "", PHP_INI_ALL, OnUpdateString, log.allowed_methods) - HTTP_PHP_INI_ENTRY("http.log.composite", "", PHP_INI_ALL, OnUpdateString, log.composite) - HTTP_PHP_INI_ENTRY("http.request.methods.allowed", "", PHP_INI_ALL, http_update_allowed_methods, request.methods.allowed) - HTTP_PHP_INI_ENTRY("http.request.methods.custom", "", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateString, request.methods.custom) -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) - HTTP_PHP_INI_ENTRY("http.request.datashare.cookie", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.cookie) - HTTP_PHP_INI_ENTRY("http.request.datashare.dns", "1", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.dns) - HTTP_PHP_INI_ENTRY("http.request.datashare.ssl", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.ssl) - HTTP_PHP_INI_ENTRY("http.request.datashare.connect", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.connect) -#endif -#ifdef HTTP_HAVE_ZLIB - HTTP_PHP_INI_ENTRY("http.send.inflate.start_auto", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, send.inflate.start_auto) - HTTP_PHP_INI_ENTRY("http.send.inflate.start_flags", "0", PHP_INI_ALL, OnUpdateLong, send.inflate.start_flags) - HTTP_PHP_INI_ENTRY("http.send.deflate.start_auto", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, send.deflate.start_auto) - HTTP_PHP_INI_ENTRY("http.send.deflate.start_flags", "0", PHP_INI_ALL, OnUpdateLong, send.deflate.start_flags) -#endif - HTTP_PHP_INI_ENTRY("http.persistent.handles.limit", "-1", PHP_INI_SYSTEM, OnUpdateLong, persistent.handles.limit) - HTTP_PHP_INI_ENTRY("http.persistent.handles.ident", "GLOBAL", PHP_INI_ALL, http_update_persistent_handle_ident, persistent.handles.ident.s) - HTTP_PHP_INI_ENTRY("http.send.not_found_404", "1", PHP_INI_ALL, OnUpdateBool, send.not_found_404) -#ifdef ZEND_ENGINE_2 - HTTP_PHP_INI_ENTRY("http.only_exceptions", "0", PHP_INI_ALL, OnUpdateBool, only_exceptions) -#endif - HTTP_PHP_INI_ENTRY("http.force_exit", "1", PHP_INI_ALL, OnUpdateBool, force_exit) -PHP_INI_END() -/* }}} */ - -/* {{{ PHP_MINIT_FUNCTION */ -PHP_MINIT_FUNCTION(http) -{ - http_module_number = module_number; - ZEND_INIT_MODULE_GLOBALS(http, http_globals_init_once, NULL); - REGISTER_INI_ENTRIES(); - - if (0 - || SUCCESS != PHP_MINIT_CALL(http_persistent_handle) /* first */ - || SUCCESS != PHP_MINIT_CALL(http_cookie) -#ifdef HTTP_HAVE_ZLIB - || SUCCESS != PHP_MINIT_CALL(http_encoding) -#endif -#ifdef HTTP_HAVE_CURL - || SUCCESS != PHP_MINIT_CALL(http_request) -# ifdef ZEND_ENGINE_2 -# endif -#endif - || SUCCESS != PHP_MINIT_CALL(http_request_method) - || SUCCESS != PHP_MINIT_CALL(http_send) - || SUCCESS != PHP_MINIT_CALL(http_support) - || SUCCESS != PHP_MINIT_CALL(http_url) - -#ifdef ZEND_ENGINE_2 - || SUCCESS != PHP_MINIT_CALL(http_filter) - || SUCCESS != PHP_MINIT_CALL(http_exception_object) -# ifdef HTTP_HAVE_ZLIB - || SUCCESS != PHP_MINIT_CALL(http_deflatestream_object) - || SUCCESS != PHP_MINIT_CALL(http_inflatestream_object) -# endif - || SUCCESS != PHP_MINIT_CALL(http_message_object) - || SUCCESS != PHP_MINIT_CALL(http_querystring_object) -# ifdef HTTP_HAVE_CURL - || SUCCESS != PHP_MINIT_CALL(http_request_datashare) - || SUCCESS != PHP_MINIT_CALL(http_request_pool) - || SUCCESS != PHP_MINIT_CALL(http_request_object) - || SUCCESS != PHP_MINIT_CALL(http_requestdatashare_object) - || SUCCESS != PHP_MINIT_CALL(http_requestpool_object) -# endif -# ifndef WONKY - || SUCCESS != PHP_MINIT_CALL(http_response_object) -# endif - || SUCCESS != PHP_MINIT_CALL(http_util_object) -#endif - ) { - return FAILURE; - } - - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_MSHUTDOWN_FUNCTION */ -PHP_MSHUTDOWN_FUNCTION(http) -{ - UNREGISTER_INI_ENTRIES(); - - if (0 -#ifdef HTTP_HAVE_CURL - || SUCCESS != PHP_MSHUTDOWN_CALL(http_request) -# ifdef ZEND_ENGINE_2 - || SUCCESS != PHP_MSHUTDOWN_CALL(http_request_datashare) -# endif -#endif - || SUCCESS != PHP_MSHUTDOWN_CALL(http_message_object) - || SUCCESS != PHP_MSHUTDOWN_CALL(http_persistent_handle) /* last */ - ) { - return FAILURE; - } - - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_RINIT_FUNCTION */ -PHP_RINIT_FUNCTION(http) -{ - http_globals_init(HTTP_G); - - if (HTTP_G->request.methods.allowed && *HTTP_G->request.methods.allowed) { - http_check_allowed_methods(HTTP_G->request.methods.allowed); - } - - if (0 -#ifdef HTTP_HAVE_ZLIB - || SUCCESS != PHP_RINIT_CALL(http_encoding) -#endif -#ifdef HTTP_HAVE_CURL -# ifdef ZEND_ENGINE_2 -# ifdef HTTP_HAVE_EVENT - || SUCCESS != PHP_RINIT_CALL(http_request_pool) -# endif - || SUCCESS != PHP_RINIT_CALL(http_request_datashare) -# endif -#endif - || SUCCESS != PHP_RINIT_CALL(http_request_method) - ) { - return FAILURE; - } - - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_RSHUTDOWN_FUNCTION */ -PHP_RSHUTDOWN_FUNCTION(http) -{ - STATUS status = SUCCESS; - - if (0 -#ifdef HTTP_HAVE_ZLIB - || SUCCESS != PHP_RSHUTDOWN_CALL(http_encoding) -#endif -#ifdef HTTP_HAVE_CURL -# ifdef ZEND_ENGINE_2 - || SUCCESS != PHP_RSHUTDOWN_CALL(http_request_datashare) -# endif -#endif - || SUCCESS != PHP_RSHUTDOWN_CALL(http_request_method) - ) { - status = FAILURE; - } - - http_globals_free(HTTP_G); - return status; -} -/* }}} */ - -/* {{{ PHP_MINFO_FUNCTION */ -PHP_MINFO_FUNCTION(http) -{ - php_info_print_table_start(); - { - php_info_print_table_header(2, "HTTP Support", "enabled"); - php_info_print_table_row(2, "Extension Version", PHP_HTTP_VERSION); - php_info_print_table_row(2, "Registered Classes", -#ifndef ZEND_ENGINE_2 - "none" -#else - "HttpUtil, " - "HttpMessage, " -# ifdef HTTP_HAVE_CURL - "HttpRequest, " - "HttpRequestPool, " - "HttpRequestDataShare, " -# endif -# ifdef HTTP_HAVE_ZLIB - "HttpDeflateStream, " - "HttpInflateStream, " -# endif -# ifndef WONKY - "HttpResponse, " -# endif - "HttpQueryString" -#endif - ); - php_info_print_table_row(2, "Output Handlers", "ob_deflatehandler, ob_inflatehandler, ob_etaghandler"); - php_info_print_table_row(2, "Stream Filters", -#ifndef ZEND_ENGINE_2 - "none" -#else - "http.chunked_decode, http.chunked_encode, http.deflate, http.inflate" -#endif - ); - } - php_info_print_table_end(); - - php_info_print_table_start(); - php_info_print_table_header(3, "Used Library", "Compiled", "Linked"); - { -#ifdef HTTP_HAVE_CURL - curl_version_info_data *cv = curl_version_info(CURLVERSION_NOW); - php_info_print_table_row(3, "libcurl", LIBCURL_VERSION, cv->version); -#else - php_info_print_table_row(2, "libcurl", "disabled", "disabled"); -#endif -#ifdef HTTP_HAVE_EVENT - php_info_print_table_row(3, "libevent", HTTP_EVENT_VERSION, event_get_version()); -#else - php_info_print_table_row(3, "libevent", "disabled", "disabled"); -#endif -#ifdef HTTP_HAVE_ZLIB - php_info_print_table_row(3, "libz", ZLIB_VERSION, zlibVersion()); -#else - php_info_print_table_row(3, "libz", "disabled", "disabled"); -#endif -#if defined(HTTP_HAVE_MAGIC) - php_info_print_table_row(3, "libmagic", "unknown", "unknown"); -#else - php_info_print_table_row(3, "libmagic", "disabled", "disabled"); -#endif - } - php_info_print_table_end(); - - php_info_print_table_start(); - php_info_print_table_colspan_header(4, "Persistent Handles"); - php_info_print_table_header(4, "Provider", "Ident", "Used", "Free"); - { - HashTable *ht; - HashPosition pos1, pos2; - HashKey provider = initHashKey(0), ident = initHashKey(0); - zval **val, **sub, **zused, **zfree; - - if ((ht = http_persistent_handle_statall()) && zend_hash_num_elements(ht)) { - FOREACH_HASH_KEYVAL(pos1, ht, provider, val) { - if (zend_hash_num_elements(Z_ARRVAL_PP(val))) { - FOREACH_KEYVAL(pos2, *val, ident, sub) { - if ( SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("used"), (void *) &zused) && - SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("free"), (void *) &zfree)) { - zval *used = http_zsep(IS_STRING, *zused); - zval *free = http_zsep(IS_STRING, *zfree); - php_info_print_table_row(4, provider.str, ident.str, Z_STRVAL_P(used), Z_STRVAL_P(free)); - zval_ptr_dtor(&used); - zval_ptr_dtor(&free); - } else { - php_info_print_table_row(4, provider.str, ident.str, "0", "0"); - } - } - } else { - php_info_print_table_row(4, provider.str, "N/A", "0", "0"); - } - } - } else { - php_info_print_table_row(4, "N/A", "N/A", "0", "0"); - } - if (ht) { - zend_hash_destroy(ht); - FREE_HASHTABLE(ht); - } - } - php_info_print_table_end(); - - php_info_print_table_start(); - php_info_print_table_colspan_header(2, "Request Methods"); - { - HashPosition pos; - phpstr *methods = phpstr_new(); - char **name; - - FOREACH_HASH_VAL(pos, &HTTP_G->request.methods.registered, name) { - if (pos->h) { - phpstr_appendf(methods, "%s, ", *name); - } - } - phpstr_fix(methods); - php_info_print_table_row(2, "Registered", PHPSTR_VAL(methods)); - php_info_print_table_row(2, "Allowed", *HTTP_G->request.methods.allowed ? HTTP_G->request.methods.allowed : "(ANY)"); - phpstr_free(&methods); - } - php_info_print_table_end(); - - DISPLAY_INI_ENTRIES(); -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http.dsp b/http.dsp deleted file mode 100644 index 5edf464..0000000 --- a/http.dsp +++ /dev/null @@ -1,257 +0,0 @@ -# Microsoft Developer Studio Project File - Name="http" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=http - Win32 Release_TS -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "http.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "http.mak" CFG="http - Win32 Release_TS" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "http - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "http - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "http - Win32 Release_TS" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release_TS" -# PROP BASE Intermediate_Dir "Release_TS" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release_TS" -# PROP Intermediate_Dir "Release_TS" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\.." /I "..\..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\..\TSRM" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_HTTP" /D ZTS=1 /YX /FD /c -# ADD CPP /nologo /Gd /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D ZEND_DEBUG=0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HTTP_EXPORTS" /D "COMPILE_DL_HTTP" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_HTTP=1 /D HTTP_HAVE_CURL=1 /D HAVE_CURL_EASY_STRERROR=1 /D HAVE_CURL_SHARE_STRERROR=1 /D HAVE_CURL_MULTI_STRERROR=1 /D HAVE_CURL_EASY_RESET=1 /D HAVE_CURL_FORMGET=1 /D HAVE_GETHOSTNAME=1 /D HAVE_GETSERVBYPORT=1 /D HAVE_GETSERVBYNAME=1 /D "_WINSOCKAPI_=" /FR /YX /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x406 /d "NDEBUG" -# ADD RSC /l 0x406 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386 -# ADD LINK32 libcurl.lib ssleay32.lib libeay32.lib zlib.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib wsock32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_http.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline" /libpath:"..\..\..\php_build\curl\lib" /libpath:"..\..\..\php4\Release_TS" /libpath:"..\..\..\php4\Release_TS_Inline" - -!ELSEIF "$(CFG)" == "http - Win32 Debug_TS" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Debug_TS" -# PROP BASE Intermediate_Dir "Debug_TS" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Debug_TS" -# PROP Intermediate_Dir "Debug_TS" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\.." /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILE_DL_HTTP" /D ZTS=1 /YX /FD /c -# ADD CPP /nologo /MDd /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\..\bindlib_w32" /I "..\..\TSRM" /D ZEND_DEBUG=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HTTP_EXPORTS" /D "COMPILE_DL_HTTP" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_HTTP=1 /D HTTP_HAVE_CURL=1 /D HAVE_CURL_EASY_STRERROR=1 /D HAVE_CURL_SHARE_STRERROR=1 /D HAVE_CURL_MULTI_STRERROR=1 /D HAVE_CURL_EASY_RESET=1 /D HAVE_CURL_FORMGET=1 /D HAVE_GETHOSTNAME=1 /D HAVE_GETSERVBYPORT=1 /D HAVE_GETSERVBYNAME=1 /D "_WINSOCKAPI_=" /YX /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x406 /d "NDEBUG" -# ADD RSC /l 0x406 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /machine:I386 -# ADD LINK32 libcurl.lib ssleay32.lib libeay32.lib zlib.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts_debug.lib wsock32.lib /nologo /dll /machine:I386 /out:"..\..\Debug_TS/http.dll" /libpath:"..\..\Debug_TS" /libpath:"..\..\..\php_build\curl\lib" /libpath:"..\..\..\php4\Release_TS" /libpath:"..\..\..\php4\Release_TS_Inline" - -!ENDIF - -# Begin Target - -# Name "http - Win32 Release_TS" -# Name "http - Win32 Debug_TS" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\http.c -# End Source File -# Begin Source File - -SOURCE=.\http_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_encoding_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_request_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_request_info.c -# End Source File -# Begin Source File - -SOURCE=.\http_request_body_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_request_method_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_functions.c -# End Source File -# Begin Source File - -SOURCE=.\http_persistent_handle_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_cache_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_cookie_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_date_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_headers_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_message_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_send_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_url_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_querystring_api.c -# End Source File -# Begin Source File - -SOURCE=.\http_info_api.c -# End Source File -# Begin Source File - -SOURCE=.\phpstr\phpstr.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\php_http.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_encoding_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_request_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_request_int.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_request_body_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_request_method_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_persistent_handle_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_cache_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_cookie_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_date_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_message_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_send_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_headers_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_url_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_querystring_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_info_api.h -# End Source File -# Begin Source File - -SOURCE=.\php_http_std_defs.h -# End Source File -# Begin Source File - -SOURCE=.\phpstr\phpstr.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/http_api.c b/http_api.c deleted file mode 100644 index 6b01a3b..0000000 --- a/http_api.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#include "php_http.h" - -#include "php_output.h" -#include "ext/standard/url.h" -#include "ext/standard/php_lcg.h" - -#include "php_http_api.h" -#include "php_http_send_api.h" - -#ifdef ZEND_ENGINE_2 -# include "php_http_exception_object.h" -#endif - -PHP_MINIT_FUNCTION(http_support) -{ - HTTP_LONG_CONSTANT("HTTP_SUPPORT", HTTP_SUPPORT); - HTTP_LONG_CONSTANT("HTTP_SUPPORT_REQUESTS", HTTP_SUPPORT_REQUESTS); - HTTP_LONG_CONSTANT("HTTP_SUPPORT_MAGICMIME", HTTP_SUPPORT_MAGICMIME); - HTTP_LONG_CONSTANT("HTTP_SUPPORT_ENCODINGS", HTTP_SUPPORT_ENCODINGS); - HTTP_LONG_CONSTANT("HTTP_SUPPORT_SSLREQUESTS", HTTP_SUPPORT_SSLREQUESTS); - HTTP_LONG_CONSTANT("HTTP_SUPPORT_EVENTS", HTTP_SUPPORT_EVENTS); - - HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_COMMA", HTTP_PARAMS_ALLOW_COMMA); - HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_FAILURE", HTTP_PARAMS_ALLOW_FAILURE); - HTTP_LONG_CONSTANT("HTTP_PARAMS_RAISE_ERROR", HTTP_PARAMS_RAISE_ERROR); - HTTP_LONG_CONSTANT("HTTP_PARAMS_DEFAULT", HTTP_PARAMS_DEFAULT); - - return SUCCESS; -} - -PHP_HTTP_API long _http_support(long feature) -{ - long support = HTTP_SUPPORT; - -#ifdef HTTP_HAVE_CURL - support |= HTTP_SUPPORT_REQUESTS; -# ifdef HTTP_HAVE_SSL - support |= HTTP_SUPPORT_SSLREQUESTS; -# endif -# ifdef HTTP_HAVE_EVENT - support |= HTTP_SUPPORT_EVENTS; -# endif -#endif -#ifdef HTTP_HAVE_MAGIC - support |= HTTP_SUPPORT_MAGICMIME; -#endif -#ifdef HTTP_HAVE_ZLIB - support |= HTTP_SUPPORT_ENCODINGS; -#endif - - if (feature) { - return (feature == (support & feature)); - } - return support; -} - -/* char *pretty_key(char *, size_t, zend_bool, zend_bool) */ -char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen) -{ - size_t i; - int wasalpha; - - if (key && key_len) { - if ((wasalpha = HTTP_IS_CTYPE(alpha, key[0]))) { - key[0] = (char) (uctitle ? HTTP_TO_CTYPE(upper, key[0]) : HTTP_TO_CTYPE(lower, key[0])); - } - for (i = 1; i < key_len; i++) { - if (HTTP_IS_CTYPE(alpha, key[i])) { - key[i] = (char) (((!wasalpha) && uctitle) ? HTTP_TO_CTYPE(upper, key[i]) : HTTP_TO_CTYPE(lower, key[i])); - wasalpha = 1; - } else { - if (xhyphen && (key[i] == '_')) { - key[i] = '-'; - } - wasalpha = 0; - } - } - } - return key; -} -/* }}} */ - -/* {{{ http_boundary(char *, size_t) */ -size_t _http_boundary(char *buf, size_t buf_len TSRMLS_DC) -{ - return snprintf(buf, buf_len, "%lu%0.9f", (ulong) HTTP_G->request.time, (float) php_combined_lcg(TSRMLS_C)); -} -/* }}} */ - -/* {{{ void http_error(long, long, char*) */ -void _http_error_ex(long type TSRMLS_DC, long code, const char *format, ...) -{ - va_list args; - - va_start(args, format); -#ifdef ZEND_ENGINE_2 - if ((type == E_THROW) || (GLOBAL_ERROR_HANDLING == EH_THROW)) { - char *message; - zend_class_entry *ce = http_exception_get_for_code(code); - - http_try { - vspprintf(&message, 0, format, args); - zend_throw_exception(ce, message, code TSRMLS_CC); - efree(message); - } http_catch(GLOBAL_EXCEPTION_CLASS ? GLOBAL_EXCEPTION_CLASS : HTTP_EX_DEF_CE); - } else -#endif - php_verror(NULL, "", type, format, args TSRMLS_CC); - va_end(args); -} -/* }}} */ - -#ifdef ZEND_ENGINE_2 -static inline void copy_bt_args(zval *from, zval *to TSRMLS_DC) -{ - zval **args, **trace_0, *old_trace_0, *trace = NULL; - - if ((trace = zend_read_property(ZEND_EXCEPTION_GET_DEFAULT(), from, "trace", lenof("trace"), 0 TSRMLS_CC))) { - if (Z_TYPE_P(trace) == IS_ARRAY && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(trace), 0, (void *) &trace_0)) { - old_trace_0 = *trace_0; - if (Z_TYPE_PP(trace_0) == IS_ARRAY && SUCCESS == zend_hash_find(Z_ARRVAL_PP(trace_0), "args", sizeof("args"), (void *) &args)) { - if ((trace = zend_read_property(ZEND_EXCEPTION_GET_DEFAULT(), to, "trace", lenof("trace"), 0 TSRMLS_CC))) { - if (Z_TYPE_P(trace) == IS_ARRAY && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(trace), 0, (void *) &trace_0)) { - ZVAL_ADDREF(*args); - add_assoc_zval(*trace_0, "args", *args); - } - } - } - } - } -} - -/* {{{ zval *http_exception_wrap(zval *, zval *, zend_class_entry *) */ -zval *_http_exception_wrap(zval *old_exception, zval *new_exception, zend_class_entry *ce TSRMLS_DC) -{ - int inner = 1; - char *message; - zval *sub_exception, *tmp_exception; - - if (!new_exception) { - MAKE_STD_ZVAL(new_exception); - object_init_ex(new_exception, ce); - - zend_update_property(ce, new_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC); - copy_bt_args(old_exception, new_exception TSRMLS_CC); - - sub_exception = old_exception; - - while ((sub_exception = zend_read_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(sub_exception) == IS_OBJECT) { - ++inner; - } - - spprintf(&message, 0, "Exception caused by %d inner exception(s)", inner); - zend_update_property_string(ZEND_EXCEPTION_GET_DEFAULT(), new_exception, "message", lenof("message"), message TSRMLS_CC); - efree(message); - } else { - sub_exception = new_exception; - tmp_exception = new_exception; - - while ((tmp_exception = zend_read_property(Z_OBJCE_P(tmp_exception), tmp_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(tmp_exception) == IS_OBJECT) { - sub_exception = tmp_exception; - } - - zend_update_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC); - copy_bt_args(old_exception, new_exception TSRMLS_CC); - copy_bt_args(old_exception, sub_exception TSRMLS_CC); - } -#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3 - Z_ADDREF_P(old_exception); - zend_exception_set_previous(new_exception, old_exception TSRMLS_CC); -#endif - zval_ptr_dtor(&old_exception); - return new_exception; -} -/* }}} */ - -/* {{{ STATUS http_object_new(zend_object_value *, const char *, uint, http_object_new_t, zend_class_entry *, void *, void **) */ -STATUS _http_object_new(zend_object_value *ov, const char *cname_str, uint cname_len, http_object_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC) -{ - zend_class_entry *ce = parent_ce; - - if (cname_str && cname_len) { - if (!(ce = zend_fetch_class(HTTP_ZAPI_CONST_CAST(char *) cname_str, cname_len, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC))) { - return FAILURE; - } - if (!instanceof_function(ce, parent_ce TSRMLS_CC)) { - http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Class %s does not extend %s", cname_str, parent_ce->name); - return FAILURE; - } - } - - *ov = create(ce, intern_ptr, obj_ptr TSRMLS_CC); - return SUCCESS; -} -/* }}} */ -#endif /* ZEND_ENGINE_2 */ - -/* {{{ void http_log(char *, char *, char *) */ -void _http_log_ex(char *file, const char *ident, const char *message TSRMLS_DC) -{ - time_t now; - struct tm nowtm; - char datetime[20] = {0}; - - now = HTTP_G->request.time; - strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now, &nowtm)); - -#define HTTP_LOG_WRITE(file, type, msg) \ - if (file && *file) { \ - php_stream *log = php_stream_open_wrapper_ex(file, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT); \ - \ - if (log) { \ - php_stream_printf(log TSRMLS_CC, "%s\t[%s]\t%s\t<%s>%s", datetime, type, msg, SG(request_info).request_uri, PHP_EOL); \ - php_stream_close(log); \ - } \ - \ - } - - HTTP_LOG_WRITE(file, ident, message); - HTTP_LOG_WRITE(HTTP_G->log.composite, ident, message); -} -/* }}} */ - -static void http_ob_blackhole(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC) -{ - *handled_output = ecalloc(1,1); - *handled_output_len = 0; -} - -/* {{{ STATUS http_exit(int, char*, char*) */ -STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC) -{ - if ( (send_header && (SUCCESS != http_send_status_header(status, header))) || - (status && (SUCCESS != http_send_status(status)))) { - http_error_ex(HE_WARNING, HTTP_E_HEADER, "Failed to exit with status/header: %d - %s", status, STR_PTR(header)); - STR_FREE(header); - STR_FREE(body); - return FAILURE; - } - -#ifndef PHP_OUTPUT_NEWAPI - if (!OG(ob_lock) && - !php_ob_handler_used("zlib output compression" TSRMLS_CC) && !php_ob_handler_used("ob_gzhandler" TSRMLS_CC)) { - php_end_ob_buffers(0 TSRMLS_CC); - } -#endif - - if ((SUCCESS == sapi_send_headers(TSRMLS_C)) && body) { - PHPWRITE(body, strlen(body)); - } - - switch (status) { - case 301: http_log(HTTP_G->log.redirect, "301-REDIRECT", header); break; - case 302: http_log(HTTP_G->log.redirect, "302-REDIRECT", header); break; - case 303: http_log(HTTP_G->log.redirect, "303-REDIRECT", header); break; - case 305: http_log(HTTP_G->log.redirect, "305-REDIRECT", header); break; - case 307: http_log(HTTP_G->log.redirect, "307-REDIRECT", header); break; - case 304: http_log(HTTP_G->log.cache, "304-CACHE", header); break; - case 404: http_log(HTTP_G->log.not_found, "404-NOTFOUND", NULL); break; - case 405: http_log(HTTP_G->log.allowed_methods, "405-ALLOWED", header); break; - default: http_log(NULL, header, body); break; - } - - STR_FREE(header); - STR_FREE(body); - - if (HTTP_G->force_exit) { - zend_bailout(); - } else { -#ifdef PHP_OUTPUT_NEWAPI - php_output_start_devnull(TSRMLS_C); -#else - php_ob_set_internal_handler(http_ob_blackhole, 4096, "blackhole", 0 TSRMLS_CC); -#endif - } - - return SUCCESS; -} -/* }}} */ - -/* {{{ STATUS http_check_method(char *) */ -STATUS _http_check_method_ex(const char *method, const char *methods) -{ - const char *found; - - if ( (found = strstr(methods, method)) && - (found == method || !HTTP_IS_CTYPE(alpha, found[-1])) && - (strlen(found) >= strlen(method) && !HTTP_IS_CTYPE(alpha, found[strlen(method)]))) { - return SUCCESS; - } - return FAILURE; -} -/* }}} */ - -/* {{{ zval *http_get_server_var_ex(char *, size_t) */ -PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_len, zend_bool check TSRMLS_DC) -{ - zval **hsv, **var; - char *env; - - /* if available, this is a lot faster than accessing $_SERVER */ - if (sapi_module.getenv) { - if ((!(env = sapi_module.getenv((char *) key, key_len TSRMLS_CC))) || (check && !*env)) { - return NULL; - } - if (HTTP_G->server_var) { - zval_ptr_dtor(&HTTP_G->server_var); - } - MAKE_STD_ZVAL(HTTP_G->server_var); - ZVAL_STRING(HTTP_G->server_var, env, 1); - return HTTP_G->server_var; - } - -#ifdef ZEND_ENGINE_2 - zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC); -#endif - - if ((SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) { - return NULL; - } - if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(hsv), HTTP_ZAPI_CONST_CAST(char *) key, key_len + 1, (void *) &var))) { - return NULL; - } - if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) { - return NULL; - } - return *var; -} -/* }}} */ - -/* {{{ STATUS http_get_request_body(char **, size_t *) */ -PHP_HTTP_API STATUS _http_get_request_body_ex(char **body, size_t *length, zend_bool dup TSRMLS_DC) -{ - *length = 0; - *body = NULL; - - if (SG(request_info).raw_post_data) { - *length = SG(request_info).raw_post_data_length; - *body = SG(request_info).raw_post_data; - - if (dup) { - *body = estrndup(*body, *length); - } - return SUCCESS; - } else if (sapi_module.read_post && !HTTP_G->read_post_data) { - char *buf = emalloc(4096); - int len; - - HTTP_G->read_post_data = 1; - - while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) { - SG(read_post_bytes) += len; - *body = erealloc(*body, *length + len + 1); - memcpy(*body + *length, buf, len); - *length += len; - (*body)[*length] = '\0'; - if (len < 4096) { - break; - } - } - efree(buf); - - /* check for error */ - if (len < 0) { - STR_FREE(*body); - *length = 0; - return FAILURE; - } - - SG(request_info).raw_post_data = *body; - SG(request_info).raw_post_data_length = *length; - - if (dup) { - *body = estrndup(*body, *length); - } - return SUCCESS; - } - - return FAILURE; -} -/* }}} */ - -/* {{{ php_stream *http_get_request_body_stream(void) */ -PHP_HTTP_API php_stream *_http_get_request_body_stream(TSRMLS_D) -{ - php_stream *s = NULL; - - if (SG(request_info).raw_post_data) { - s = php_stream_open_wrapper("php://input", "rb", 0, NULL); - } else if (sapi_module.read_post && !HTTP_G->read_post_data) { - HTTP_G->read_post_data = 1; - - if ((s = php_stream_temp_new())) { - char *buf = emalloc(4096); - int len; - - while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) { - SG(read_post_bytes) += len; - php_stream_write(s, buf, len); - if (len < 4096) { - break; - } - } - efree(buf); - - if (len < 0) { - php_stream_close(s); - s = NULL; - } else { - php_stream_rewind(s); - } - } - } - - return s; -} -/* }}} */ - -/* {{{ void http_parse_params_default_callback(...) */ -PHP_HTTP_API void _http_parse_params_default_callback(void *arg, const char *key, int keylen, const char *val, int vallen TSRMLS_DC) -{ - char *kdup; - zval tmp, *entry; - HashTable *ht = (HashTable *) arg; - - if (ht) { - INIT_ZARR(tmp, ht); - - if (vallen) { - MAKE_STD_ZVAL(entry); - array_init(entry); - if (keylen) { - kdup = estrndup(key, keylen); - add_assoc_stringl_ex(entry, kdup, keylen + 1, (char *) val, vallen, 1); - efree(kdup); - } else { - add_next_index_stringl(entry, (char *) val, vallen, 1); - } - add_next_index_zval(&tmp, entry); - } else { - add_next_index_stringl(&tmp, (char *) key, keylen, 1); - } - } -} -/* }}} */ - -/* {{{ STATUS http_parse_params(const char *, HashTable *) */ -PHP_HTTP_API STATUS _http_parse_params_ex(const char *param, int flags, http_parse_params_callback cb, void *cb_arg TSRMLS_DC) -{ -#define ST_QUOTE 1 -#define ST_VALUE 2 -#define ST_KEY 3 -#define ST_ASSIGN 4 -#define ST_ADD 5 - - int st = ST_KEY, keylen = 0, vallen = 0; - char *s, *c, *key = NULL, *val = NULL; - - for(c = s = estrdup(param);;) { - continued: -#if 0 - { - char *tk = NULL, *tv = NULL; - - if (key) { - if (keylen) { - tk= estrndup(key, keylen); - } else { - tk = ecalloc(1, 7); - memcpy(tk, key, 3); - tk[3]='.'; tk[4]='.'; tk[5]='.'; - } - } - if (val) { - if (vallen) { - tv = estrndup(val, vallen); - } else { - tv = ecalloc(1, 7); - memcpy(tv, val, 3); - tv[3]='.'; tv[4]='.'; tv[5]='.'; - } - } - fprintf(stderr, "[%6s] %c \"%s=%s\"\n", - ( - st == ST_QUOTE ? "QUOTE" : - st == ST_VALUE ? "VALUE" : - st == ST_KEY ? "KEY" : - st == ST_ASSIGN ? "ASSIGN" : - st == ST_ADD ? "ADD": - "HUH?" - ), *c?*c:'0', tk, tv - ); - STR_FREE(tk); STR_FREE(tv); - } -#endif - switch (st) { - case ST_QUOTE: - quote: - if (*c == '"') { - if (*(c-1) == '\\') { - memmove(c-1, c, strlen(c)+1); - goto quote; - } else { - goto add; - } - } else { - if (!val) { - val = c; - } - if (!*c) { - --val; - st = ST_ADD; - } - } - break; - - case ST_VALUE: - switch (*c) { - case '"': - if (!val) { - st = ST_QUOTE; - } - break; - - case ' ': - break; - - case ';': - case '\0': - goto add; - break; - case ',': - if (flags & HTTP_PARAMS_ALLOW_COMMA) { - goto add; - } - default: - if (!val) { - val = c; - } - break; - } - break; - - case ST_KEY: - switch (*c) { - case ',': - if (flags & HTTP_PARAMS_ALLOW_COMMA) { - goto allow_comma; - } - case '\r': - case '\n': - case '\t': - case '\013': - case '\014': - goto failure; - break; - - case ' ': - if (key) { - keylen = c - key; - st = ST_ASSIGN; - } - break; - - case ';': - case '\0': - allow_comma: - if (key) { - keylen = c-- - key; - st = ST_ADD; - } - break; - - case ':': - if (!(flags & HTTP_PARAMS_COLON_SEPARATOR)) { - goto not_separator; - } - if (key) { - keylen = c - key; - st = ST_VALUE; - } else { - goto failure; - } - break; - - case '=': - if (flags & HTTP_PARAMS_COLON_SEPARATOR) { - goto not_separator; - } - if (key) { - keylen = c - key; - st = ST_VALUE; - } else { - goto failure; - } - break; - - default: - not_separator: - if (!key) { - key = c; - } - break; - } - break; - - case ST_ASSIGN: - if (*c == '=') { - st = ST_VALUE; - } else if (!*c || *c == ';' || ((flags & HTTP_PARAMS_ALLOW_COMMA) && *c == ',')) { - st = ST_ADD; - } else if (*c != ' ') { - goto failure; - } - break; - - case ST_ADD: - add: - if (val) { - vallen = c - val; - if (st != ST_QUOTE) { - while (val[vallen-1] == ' ') --vallen; - } - } else { - val = ""; - vallen = 0; - } - - cb(cb_arg, key, keylen, val, vallen TSRMLS_CC); - - st = ST_KEY; - key = val = NULL; - keylen = vallen = 0; - break; - } - if (*c) { - ++c; - } else if (st == ST_ADD) { - goto add; - } else { - break; - } - } - - efree(s); - return SUCCESS; - -failure: - if (flags & HTTP_PARAMS_RAISE_ERROR) { - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Unexpected character (%c) at pos %tu of %zu", *c, c-s, strlen(s)); - } - if (flags & HTTP_PARAMS_ALLOW_FAILURE) { - if (st == ST_KEY) { - if (key) { - keylen = c - key; - } else { - key = c; - } - } else { - --c; - } - st = ST_ADD; - goto continued; - } - efree(s); - return FAILURE; -} -/* }}} */ - -/* {{{ array_join */ -int apply_array_append_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) -{ - int flags; - char *key = NULL; - HashTable *dst; - zval **data = NULL, **value = (zval **) pDest; - - dst = va_arg(args, HashTable *); - flags = va_arg(args, int); - - if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) { - if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) { - key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1); - zend_hash_find(dst, key, hash_key->nKeyLength, (void *) &data); - } else { - zend_hash_quick_find(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &data); - } - - ZVAL_ADDREF(*value); - if (data) { - add_next_index_zval(http_zset(IS_ARRAY, *data), *value); - } else if (key) { - zend_hash_add(dst, key, hash_key->nKeyLength, value, sizeof(zval *), NULL); - } else { - zend_hash_quick_add(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, value, sizeof(zval *), NULL); - } - - if (key) { - efree(key); - } - } - - return ZEND_HASH_APPLY_KEEP; -} - -int apply_array_merge_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) -{ - int flags; - char *key = NULL; - HashTable *dst; - zval **value = (zval **) pDest; - - dst = va_arg(args, HashTable *); - flags = va_arg(args, int); - - if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) { - ZVAL_ADDREF(*value); - if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) { - key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1); - zend_hash_update(dst, key, hash_key->nKeyLength, (void *) value, sizeof(zval *), NULL); - efree(key); - } else { - zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) value, sizeof(zval *), NULL); - } - } - - return ZEND_HASH_APPLY_KEEP; -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_cache_api.c b/http_cache_api.c deleted file mode 100644 index b6bc237..0000000 --- a/http_cache_api.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#include "php_http.h" - -#include "php_output.h" -#include "php_streams.h" - -#include "php_http_api.h" -#include "php_http_cache_api.h" -#include "php_http_date_api.h" -#include "php_http_send_api.h" - -/* {{{ char *http_etag(void *, size_t, http_send_mode) */ -PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC) -{ - void *ctx = http_etag_init(); - - if (data_mode == SEND_DATA) { - http_etag_update(ctx, data_ptr, data_len); - } else { - STATUS ss = FAILURE; - php_stream_statbuf ssb; - - if (data_mode == SEND_RSRC) { - ss = php_stream_stat((php_stream *) data_ptr, &ssb); - } else { - ss = php_stream_stat_path((char *) data_ptr, &ssb); - } - - if (SUCCESS != ss) { - efree(ctx); - return NULL; - } else { - size_t ssb_len; - char ssb_buf[128]; - - ssb_len = snprintf(ssb_buf, sizeof(ssb_buf), "%ld=%ld=%ld", (long) ssb.sb.st_mtime, - (long) ssb.sb.st_ino, - (long) ssb.sb.st_size); - http_etag_update(ctx, ssb_buf, ssb_len); - } - } - - return http_etag_finish(ctx); -} -/* }}} */ - -/* {{{ time_t http_last_modified(void *, http_send_mode) */ -PHP_HTTP_API time_t _http_last_modified(const void *data_ptr, http_send_mode data_mode TSRMLS_DC) -{ - php_stream_statbuf ssb; - - switch (data_mode) { - case SEND_DATA: return HTTP_G->request.time; - case SEND_RSRC: return php_stream_stat((php_stream *) data_ptr, &ssb) ? 0 : ssb.sb.st_mtime; - default: return php_stream_stat_path((char *) data_ptr, &ssb) ? 0 : ssb.sb.st_mtime; - } -} -/* }}} */ - -/* {{{ zend_bool http_match_last_modified(char *, time_t) */ -PHP_HTTP_API zend_bool _http_match_last_modified_ex(const char *entry, time_t t, zend_bool enforce_presence TSRMLS_DC) -{ - zend_bool retval; - zval *zmodified; - char *modified, *chr_ptr; - - if (!(zmodified = http_get_server_var(entry, 1))) { - return !enforce_presence; - } - - modified = estrndup(Z_STRVAL_P(zmodified), Z_STRLEN_P(zmodified)); - if ((chr_ptr = strrchr(modified, ';'))) { - chr_ptr = 0; - } - - retval = (t <= http_parse_date_ex(modified, 1)); - efree(modified); - return retval; -} -/* }}} */ - -/* {{{ zend_bool http_match_etag(char *, char *) */ -PHP_HTTP_API zend_bool _http_match_etag_ex(const char *entry, const char *etag, zend_bool enforce_presence TSRMLS_DC) -{ - zval *zetag; - char *quoted_etag; - zend_bool result; - - if (!(zetag = http_get_server_var_ex(entry, strlen(entry)+1, 1))) { - return !enforce_presence; - } - - if (NULL != strchr(Z_STRVAL_P(zetag), '*')) { - return 1; - } - - spprintf("ed_etag, 0, "\"%s\"", etag); - if (!strchr(Z_STRVAL_P(zetag), ',')) { - result = !strcmp(Z_STRVAL_P(zetag), quoted_etag); - } else { - result = (NULL != strstr(Z_STRVAL_P(zetag), quoted_etag)); - } - efree(quoted_etag); - - return result; -} -/* }}} */ - -/* {{{ STATUS http_cache_last_modified(time_t, time_t, char *, size_t) */ -PHP_HTTP_API STATUS _http_cache_last_modified(time_t last_modified, - time_t send_modified, const char *cache_control, size_t cc_len TSRMLS_DC) -{ - char *sent_header = NULL; - - if (SG(headers_sent)) { - return FAILURE; - } - - if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) { - return FAILURE; - } - - if (SUCCESS != http_send_last_modified_ex(send_modified, &sent_header)) { - return FAILURE; - } - - if (http_match_last_modified("HTTP_IF_MODIFIED_SINCE", last_modified)) { - http_exit_ex(304, sent_header, NULL, 0); - } else { - STR_FREE(sent_header); - } - - return SUCCESS; -} -/* }}} */ - -/* {{{ STATUS http_cache_etag(char *, size_t, char *, size_t) */ -PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len, - const char *cache_control, size_t cc_len TSRMLS_DC) -{ - char *sent_header = NULL; - - if (SG(headers_sent)) { - return FAILURE; - } - - if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) { - return FAILURE; - } - - if (etag_len) { - if (SUCCESS != http_send_etag_ex(etag, etag_len, &sent_header)) { - return FAILURE; - } - if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) { - http_exit_ex(304, sent_header, NULL, 0); - } else { - STR_FREE(sent_header); - } - return SUCCESS; - } - - /* start ob_etaghandler */ - return http_start_ob_etaghandler(); -} -/* }}} */ - -PHP_HTTP_API STATUS _http_start_ob_etaghandler(TSRMLS_D) -{ - /* already running? */ -#ifdef PHP_OUTPUT_NEWAPI - STATUS rv; - - if (php_output_handler_conflict(ZEND_STRL("ob_etaghandler"), ZEND_STRL("ob_etaghandler") TSRMLS_CC)) { - return FAILURE; - } -#else - if (php_ob_handler_used("ob_etaghandler" TSRMLS_CC)) { - http_error(HE_WARNING, HTTP_E_RUNTIME, "ob_etaghandler can only be used once"); - return FAILURE; - } -#endif - HTTP_G->etag.started = 1; -#ifdef PHP_OUTPUT_NEWAPI - return php_output_start_internal(ZEND_STRL("ob_etaghandler"), _http_ob_etaghandler, HTTP_G->send.buffer_size, 0 TSRMLS_CC); -#else - return php_start_ob_buffer_named("ob_etaghandler", HTTP_G->send.buffer_size, 0 TSRMLS_CC); -#endif -} - -PHP_HTTP_API zend_bool _http_interrupt_ob_etaghandler(TSRMLS_D) -{ - if (HTTP_G->etag.started) { - HTTP_G->etag.started = 0; - if (HTTP_G->etag.ctx) { - efree(HTTP_G->etag.ctx); - HTTP_G->etag.ctx = NULL; - } - return 1; - } - return 0; -} - -/* {{{ void http_ob_etaghandler(char *, uint, char **, uint *, int) */ -void _http_ob_etaghandler(char *output, uint output_len, - char **handled_output, uint *handled_output_len, int mode TSRMLS_DC) -{ - /* passthru */ - *handled_output_len = output_len; - *handled_output = estrndup(output, output_len); - - /* are we supposed to run? */ - if (HTTP_G->etag.started) { - /* initialize the etag context */ - if (mode & PHP_OUTPUT_HANDLER_START) { - HTTP_G->etag.ctx = http_etag_init(); - } - - /* update */ - http_etag_update(HTTP_G->etag.ctx, output, output_len); - - /* finish */ - if (mode & PHP_OUTPUT_HANDLER_END) { - char *sent_header = NULL; - char *etag = http_etag_finish(HTTP_G->etag.ctx); - - HTTP_G->etag.ctx = NULL; - - http_send_cache_control(HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)); - http_send_etag_ex(etag, strlen(etag), &sent_header); - - if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) { - /* force exit; ob within ob does not work */ - HTTP_G->force_exit = 1; - http_exit_ex(304, sent_header, etag, 0); - } - - STR_FREE(sent_header); - STR_FREE(etag); - } - } -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ - diff --git a/http_cookie_api.c b/http_cookie_api.c deleted file mode 100644 index 5776b87..0000000 --- a/http_cookie_api.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "php_http.h" -#include "php_http_api.h" -#include "php_http_date_api.h" -#include "php_http_cookie_api.h" - -#include "ext/standard/url.h" - -/* {{{ PHP_MINIT_FUNCTION(http_cookie) */ -PHP_MINIT_FUNCTION(http_cookie) -{ - HTTP_LONG_CONSTANT("HTTP_COOKIE_PARSE_RAW", HTTP_COOKIE_PARSE_RAW); - HTTP_LONG_CONSTANT("HTTP_COOKIE_SECURE", HTTP_COOKIE_SECURE); - HTTP_LONG_CONSTANT("HTTP_COOKIE_HTTPONLY", HTTP_COOKIE_HTTPONLY); - - return SUCCESS; -} -/* }}} */ - -/* {{{ http_cookie_list *http_cookie_list_init(http_cookie_list *) */ -PHP_HTTP_API http_cookie_list *_http_cookie_list_init(http_cookie_list *list ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - if (!list) { - list = emalloc_rel(sizeof(http_cookie_list)); - } - - zend_hash_init(&list->cookies, 0, NULL, ZVAL_PTR_DTOR, 0); - zend_hash_init(&list->extras, 0, NULL, ZVAL_PTR_DTOR, 0); - - list->path = NULL; - list->domain = NULL; - list->expires = 0; - list->flags = 0; - - return list; -} -/* }}} */ - -/* {{{ void http_cookie_list_dtor(http_cookie_list *) */ -PHP_HTTP_API void _http_cookie_list_dtor(http_cookie_list *list TSRMLS_DC) -{ - if (list) { - zend_hash_destroy(&list->cookies); - zend_hash_destroy(&list->extras); - - STR_SET(list->path, NULL); - STR_SET(list->domain, NULL); - } -} -/* }}} */ - -/* {{{ void http_cookie_list_free(http_cookie_list **) */ -PHP_HTTP_API void _http_cookie_list_free(http_cookie_list **list TSRMLS_DC) -{ - if (list) { - http_cookie_list_dtor(*list); - efree(*list); - *list = NULL; - } -} -/* }}} */ - -/* {{{ const char *http_cookie_list_get_cookie(http_cookie_list *, const char*, size_t) */ -PHP_HTTP_API const char *_http_cookie_list_get_cookie(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC) -{ - zval **cookie = NULL; - if ((SUCCESS != zend_hash_find(&list->cookies, HTTP_ZAPI_CONST_CAST(char *) name, name_len + 1, (void *) &cookie)) || (Z_TYPE_PP(cookie) != IS_STRING)) { - return NULL; - } - return Z_STRVAL_PP(cookie); -} -/* }}} */ - -/* {{{ const char *http_cookie_list_get_extra(http_cookie_list *, const char *, size_t) */ -PHP_HTTP_API const char *_http_cookie_list_get_extra(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC) -{ - zval **extra = NULL; - if ((SUCCESS != zend_hash_find(&list->extras, HTTP_ZAPI_CONST_CAST(char *) name, name_len + 1, (void *) &extra)) || (Z_TYPE_PP(extra) != IS_STRING)) { - return NULL; - } - return Z_STRVAL_PP(extra); -} -/* }}} */ - -/* {{{ void http_cookie_list_add_cookie(http_cookie_list *, const char *, size_t, const char *, size_t) */ -PHP_HTTP_API void _http_cookie_list_add_cookie(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC) -{ - zval *cookie_value; - char *key = estrndup(name, name_len); - MAKE_STD_ZVAL(cookie_value); - ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0); - zend_hash_update(&list->cookies, key, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL); - efree(key); -} -/* }}} */ - -/* {{{ void http_cookie_list_add_extr(http_cookie_list *, const char *, size_t, const char *, size_t) */ -PHP_HTTP_API void _http_cookie_list_add_extra(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC) -{ - zval *cookie_value; - char *key = estrndup(name, name_len); - MAKE_STD_ZVAL(cookie_value); - ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0); - zend_hash_update(&list->extras, key, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL); - efree(key); -} -/* }}} */ - -typedef struct _http_parse_param_cb_arg_t { - http_cookie_list *list; - long flags; - char **allowed_extras; -} http_parse_param_cb_arg; - -/* {{{ static void http_parse_cookie_callback */ -static void http_parse_cookie_callback(void *ptr, const char *key, int keylen, const char *val, int vallen TSRMLS_DC) -{ - http_parse_param_cb_arg *arg = (http_parse_param_cb_arg *) ptr; - -#define _KEY_IS(s) (keylen == lenof(s) && !strncasecmp(key, (s), keylen)) - if _KEY_IS("path") { - STR_SET(arg->list->path, estrndup(val, vallen)); - } else if _KEY_IS("domain") { - STR_SET(arg->list->domain, estrndup(val, vallen)); - } else if _KEY_IS("expires") { - char *date = estrndup(val, vallen); - arg->list->expires = http_parse_date(date); - efree(date); - } else if _KEY_IS("secure") { - arg->list->flags |= HTTP_COOKIE_SECURE; - } else if _KEY_IS("httpOnly") { - arg->list->flags |= HTTP_COOKIE_HTTPONLY; - } else { - /* check for extra */ - if (arg->allowed_extras) { - char **ae = arg->allowed_extras; - - for (; *ae; ++ae) { - if ((size_t) keylen == strlen(*ae) && !strncasecmp(key, *ae, keylen)) { - if (arg->flags & HTTP_COOKIE_PARSE_RAW) { - http_cookie_list_add_extra(arg->list, key, keylen, val, vallen); - } else { - char *dec = estrndup(val, vallen); - int declen = php_url_decode(dec, vallen); - - http_cookie_list_add_extra(arg->list, key, keylen, dec, declen); - efree(dec); - } - return; - } - } - } - /* new cookie */ - if (arg->flags & HTTP_COOKIE_PARSE_RAW) { - http_cookie_list_add_cookie(arg->list, key, keylen, val, vallen); - } else { - char *dec = estrndup(val, vallen); - int declen = php_url_decode(dec, vallen); - - http_cookie_list_add_cookie(arg->list, key, keylen, dec, declen); - efree(dec); - } - } -} -/* }}} */ - -/* {{{ http_cookie_list *http_parse_cookie(char *, long) */ -PHP_HTTP_API http_cookie_list *_http_parse_cookie_ex(http_cookie_list *list, const char *string, long flags, char **allowed_extras TSRMLS_DC) -{ - int free_list = !list; - http_parse_param_cb_arg arg; - - list = http_cookie_list_init(list); - - arg.list = list; - arg.flags = flags; - arg.allowed_extras = allowed_extras; - - if (SUCCESS != http_parse_params_ex(string, HTTP_PARAMS_RAISE_ERROR, http_parse_cookie_callback, &arg)) { - if (free_list) { - http_cookie_list_free(&list); - } else { - http_cookie_list_dtor(list); - } - list = NULL; - } - - return list; -} -/* }}} */ - -/* {{{ void http_cookie_list_tostruct(http_cookie_list *, zval *) */ -PHP_HTTP_API void _http_cookie_list_tostruct(http_cookie_list *list, zval *strct TSRMLS_DC) -{ - zval array, *cookies, *extras; - - INIT_ZARR(array, HASH_OF(strct)); - - MAKE_STD_ZVAL(cookies); - array_init(cookies); - zend_hash_copy(Z_ARRVAL_P(cookies), &list->cookies, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - add_assoc_zval(&array, "cookies", cookies); - - MAKE_STD_ZVAL(extras); - array_init(extras); - zend_hash_copy(Z_ARRVAL_P(extras), &list->extras, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - add_assoc_zval(&array, "extras", extras); - - add_assoc_long(&array, "flags", list->flags); - add_assoc_long(&array, "expires", (long) list->expires); - add_assoc_string(&array, "path", STR_PTR(list->path), 1); - add_assoc_string(&array, "domain", STR_PTR(list->domain), 1); -} -/* }}} */ - -/* {{{ http_cookie_list *http_cookie_list_fromstruct(http_cookie_list *, zval *strct) */ -PHP_HTTP_API http_cookie_list *_http_cookie_list_fromstruct(http_cookie_list *list, zval *strct TSRMLS_DC) -{ - zval **tmp, *cpy; - HashTable *ht = HASH_OF(strct); - - list = http_cookie_list_init(list); - - if (SUCCESS == zend_hash_find(ht, "cookies", sizeof("cookies"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_ARRAY) { - zend_hash_copy(&list->cookies, Z_ARRVAL_PP(tmp), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - } - if (SUCCESS == zend_hash_find(ht, "extras", sizeof("extras"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_ARRAY) { - zend_hash_copy(&list->extras, Z_ARRVAL_PP(tmp), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - } - if (SUCCESS == zend_hash_find(ht, "flags", sizeof("flags"), (void *) &tmp)) { - switch (Z_TYPE_PP(tmp)) { - case IS_LONG: - list->flags = Z_LVAL_PP(tmp); - break; - case IS_DOUBLE: - list->flags = (long) Z_DVAL_PP(tmp); - break; - case IS_STRING: - cpy = http_zsep(IS_LONG, *tmp); - list->flags = Z_LVAL_P(cpy); - zval_ptr_dtor(&cpy); - break; - default: - break; - } - } - if (SUCCESS == zend_hash_find(ht, "expires", sizeof("expires"), (void *) &tmp)) { - switch (Z_TYPE_PP(tmp)) { - case IS_LONG: - list->expires = Z_LVAL_PP(tmp); - break; - case IS_DOUBLE: - list->expires = (long) Z_DVAL_PP(tmp); - break; - case IS_STRING: - cpy = http_zsep(IS_LONG, *tmp); - if (Z_LVAL_P(cpy)) { - list->expires = Z_LVAL_P(cpy); - } else { - time_t expires = http_parse_date(Z_STRVAL_PP(tmp)); - if (expires > 0) { - list->expires = expires; - } - } - zval_ptr_dtor(&cpy); - break; - default: - break; - } - } - if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_STRING) { - list->path = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); - } - if (SUCCESS == zend_hash_find(ht, "domain", sizeof("domain"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_STRING) { - list->domain = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); - } - - return list; -} -/* }}} */ - -/* {{{ inline append_encoded */ -static inline void append_encoded(phpstr *buf, const char *key, size_t key_len, const char *val, size_t val_len) -{ - char *enc_str[2]; - int enc_len[2]; - - enc_str[0] = php_url_encode(key, key_len, &enc_len[0]); - enc_str[1] = php_url_encode(val, val_len, &enc_len[1]); - - phpstr_append(buf, enc_str[0], enc_len[0]); - phpstr_appends(buf, "="); - phpstr_append(buf, enc_str[1], enc_len[1]); - phpstr_appends(buf, "; "); - - efree(enc_str[0]); - efree(enc_str[1]); -} -/* }}} */ - -/* {{{ void http_cookie_list_tostring(http_cookie_list *, char **, size_t *) */ -PHP_HTTP_API void _http_cookie_list_tostring(http_cookie_list *list, char **str, size_t *len TSRMLS_DC) -{ - phpstr buf; - zval **val; - HashKey key = initHashKey(0); - HashPosition pos; - - phpstr_init(&buf); - - FOREACH_HASH_KEYVAL(pos, &list->cookies, key, val) { - if (key.type == HASH_KEY_IS_STRING && key.len) { - zval *tmp = http_zsep(IS_STRING, *val); - append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); - zval_ptr_dtor(&tmp); - } - } - - if (list->domain && *list->domain) { - phpstr_appendf(&buf, "domain=%s; ", list->domain); - } - if (list->path && *list->path) { - phpstr_appendf(&buf, "path=%s; ", list->path); - } - if (list->expires) { - char *date = http_date(list->expires); - phpstr_appendf(&buf, "expires=%s; ", date); - efree(date); - } - - FOREACH_HASH_KEYVAL(pos, &list->extras, key, val) { - if (key.type == HASH_KEY_IS_STRING && key.len) { - zval *tmp = http_zsep(IS_STRING, *val); - append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); - } - } - - if (list->flags & HTTP_COOKIE_SECURE) { - phpstr_appends(&buf, "secure; "); - } - if (list->flags & HTTP_COOKIE_HTTPONLY) { - phpstr_appends(&buf, "httpOnly; "); - } - - phpstr_fix(&buf); - *str = PHPSTR_VAL(&buf); - *len = PHPSTR_LEN(&buf); -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/http_date_api.c b/http_date_api.c deleted file mode 100644 index 78a5da1..0000000 --- a/http_date_api.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "php_http.h" - -#include "php_http_api.h" -#include "php_http_date_api.h" - -static inline int check_day(const char *day, size_t len); -static inline int check_month(const char *month); -static inline int check_tzone(const char *tzone); -static inline time_t parse_date(const char *month); - -/* {{{ day/month names */ -static const char *days[] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" -}; -static const char *wkdays[] = { - "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" -}; -static const char *weekdays[] = { - "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday", "Sunday" -}; -static const char *months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; -enum assume_next { - DATE_MDAY, - DATE_YEAR, - DATE_TIME -}; -#define DS -60 -static const struct time_zone { - const char *name; - const int offset; -} time_zones[] = { - {"GMT", 0}, /* Greenwich Mean */ - {"UTC", 0}, /* Universal (Coordinated) */ - {"WET", 0}, /* Western European */ - {"BST", 0 DS}, /* British Summer */ - {"WAT", 60}, /* West Africa */ - {"AST", 240}, /* Atlantic Standard */ - {"ADT", 240 DS},/* Atlantic Daylight */ - {"EST", 300}, /* Eastern Standard */ - {"EDT", 300 DS},/* Eastern Daylight */ - {"CST", 360}, /* Central Standard */ - {"CDT", 360 DS},/* Central Daylight */ - {"MST", 420}, /* Mountain Standard */ - {"MDT", 420 DS},/* Mountain Daylight */ - {"PST", 480}, /* Pacific Standard */ - {"PDT", 480 DS},/* Pacific Daylight */ - {"YST", 540}, /* Yukon Standard */ - {"YDT", 540 DS},/* Yukon Daylight */ - {"HST", 600}, /* Hawaii Standard */ - {"HDT", 600 DS},/* Hawaii Daylight */ - {"CAT", 600}, /* Central Alaska */ - {"AHST", 600}, /* Alaska-Hawaii Standard */ - {"NT", 660}, /* Nome */ - {"IDLW", 720}, /* International Date Line West */ - {"CET", -60}, /* Central European */ - {"MET", -60}, /* Middle European */ - {"MEWT", -60}, /* Middle European Winter */ - {"MEST", -60 DS},/* Middle European Summer */ - {"CEST", -60 DS},/* Central European Summer */ - {"MESZ", -60 DS},/* Middle European Summer */ - {"FWT", -60}, /* French Winter */ - {"FST", -60 DS},/* French Summer */ - {"EET", -120}, /* Eastern Europe, USSR Zone 1 */ - {"WAST", -420}, /* West Australian Standard */ - {"WADT", -420 DS},/* West Australian Daylight */ - {"CCT", -480}, /* China Coast, USSR Zone 7 */ - {"JST", -540}, /* Japan Standard, USSR Zone 8 */ - {"EAST", -600}, /* Eastern Australian Standard */ - {"EADT", -600 DS},/* Eastern Australian Daylight */ - {"GST", -600}, /* Guam Standard, USSR Zone 9 */ - {"NZT", -720}, /* New Zealand */ - {"NZST", -720}, /* New Zealand Standard */ - {"NZDT", -720 DS},/* New Zealand Daylight */ - {"IDLE", -720}, /* International Date Line East */ -}; -/* }}} */ - -/* {{{ Day/Month/TZ checks for http_parse_date() - Originally by libcurl, Copyright (C) 1998 - 2004, Daniel Stenberg, , et al. */ -static inline int check_day(const char *day, size_t len) -{ - int i; - const char * const *check = (len > 3) ? &weekdays[0] : &wkdays[0]; - for (i = 0; i < 7; i++) { - if (!strcmp(day, check[0])) { - return i; - } - check++; - } - return -1; -} - -static inline int check_month(const char *month) -{ - int i; - const char * const *check = &months[0]; - for (i = 0; i < 12; i++) { - if (!strcmp(month, check[0])) { - return i; - } - check++; - } - return -1; -} - -/* return the time zone offset between GMT and the input one, in number - of seconds or -1 if the timezone wasn't found/legal */ - -static inline int check_tzone(const char *tzone) -{ - unsigned i; - const struct time_zone *check = time_zones; - for (i = 0; i < sizeof(time_zones) / sizeof(time_zones[0]); i++) { - if (!strcmp(tzone, check->name)) { - return check->offset * 60; - } - check++; - } - return -1; -} -/* }}} */ - -/* {{{ char *http_date(time_t) */ -PHP_HTTP_API char *_http_date(time_t t TSRMLS_DC) -{ - char *date = NULL; - struct tm *gmtime = NULL, tmbuf; - - memset(&tmbuf, 0, sizeof(tmbuf)); - if ((gmtime = php_gmtime_r(&t, &tmbuf))) { - spprintf(&date, 0, - "%s, %02d %s %04d %02d:%02d:%02d GMT", - days[gmtime->tm_wday], gmtime->tm_mday, - months[gmtime->tm_mon], gmtime->tm_year + 1900, - gmtime->tm_hour, gmtime->tm_min, gmtime->tm_sec - ); - } - - return date; -} -/* }}} */ - -/* {{{ time_t http_parse_date(char *) */ -PHP_HTTP_API time_t _http_parse_date_ex(const char *date, zend_bool silent TSRMLS_DC) -{ - time_t t = parse_date(date); - - if (-1 == t && !silent) { - http_error_ex(HE_NOTICE, HTTP_E_RUNTIME, "Could not parse date: %s", date); - } - - return t; -} -/* }}} */ - -/* time_t parse_date(char *) - Originally by libcurl, Copyright (C) 1998 - 2004, Daniel Stenberg, , et al. */ -static inline time_t parse_date(const char *date) -{ - time_t t = 0; - int tz_offset = -1, year = -1, month = -1, monthday = -1, weekday = -1, - hours = -1, minutes = -1, seconds = -1; - struct tm tm; - enum assume_next dignext = DATE_MDAY; - const char *indate = date; - - int part = 0; /* max 6 parts */ - - while (*date && (part < 6)) { - int found = 0; - - while (*date && !HTTP_IS_CTYPE(alnum, *date)) { - date++; - } - - if (HTTP_IS_CTYPE(alpha, *date)) { - /* a name coming up */ - char buf[32] = ""; - size_t len; - sscanf(date, "%31[A-Za-z]", buf); - len = strlen(buf); - - if (weekday == -1) { - weekday = check_day(buf, len); - if (weekday != -1) { - found = 1; - } - } - - if (!found && (month == -1)) { - month = check_month(buf); - if (month != -1) { - found = 1; - } - } - - if (!found && (tz_offset == -1)) { - /* this just must be a time zone string */ - tz_offset = check_tzone(buf); - if (tz_offset != -1) { - found = 1; - } - } - - if (!found) { - return -1; /* bad string */ - } - date += len; - } - else if (HTTP_IS_CTYPE(digit, *date)) { - /* a digit */ - int val; - char *end; - if ((seconds == -1) && - (3 == sscanf(date, "%02d:%02d:%02d", &hours, &minutes, &seconds))) { - /* time stamp! */ - date += 8; - found = 1; - } - else { - val = (int) strtol(date, &end, 10); - - if ((tz_offset == -1) && ((end - date) == 4) && (val < 1300) && - (indate < date) && ((date[-1] == '+' || date[-1] == '-'))) { - /* four digits and a value less than 1300 and it is preceeded with - a plus or minus. This is a time zone indication. */ - found = 1; - tz_offset = (val / 100 * 60 + val % 100) * 60; - - /* the + and - prefix indicates the local time compared to GMT, - this we need ther reversed math to get what we want */ - tz_offset = date[-1] == '+' ? -tz_offset : tz_offset; - } - - if (((end - date) == 8) && (year == -1) && (month == -1) && (monthday == -1)) { - /* 8 digits, no year, month or day yet. This is YYYYMMDD */ - found = 1; - year = val / 10000; - month = (val % 10000) / 100 - 1; /* month is 0 - 11 */ - monthday = val % 100; - } - - if (!found && (dignext == DATE_MDAY) && (monthday == -1)) { - if ((val > 0) && (val < 32)) { - monthday = val; - found = 1; - } - dignext = DATE_YEAR; - } - - if (!found && (dignext == DATE_YEAR) && (year == -1)) { - year = val; - found = 1; - if (year < 1900) { - year += year > 70 ? 1900 : 2000; - } - if(monthday == -1) { - dignext = DATE_MDAY; - } - } - - if (!found) { - return -1; - } - - date = end; - } - } - - part++; - } - - if (-1 == seconds) { - seconds = minutes = hours = 0; /* no time, make it zero */ - } - - if ((-1 == monthday) || (-1 == month) || (-1 == year)) { - /* lacks vital info, fail */ - return -1; - } - - if (sizeof(time_t) < 5) { - /* 32 bit time_t can only hold dates to the beginning of 2038 */ - if (year > 2037) { - return 0x7fffffff; - } - } - - tm.tm_sec = seconds; - tm.tm_min = minutes; - tm.tm_hour = hours; - tm.tm_mday = monthday; - tm.tm_mon = month; - tm.tm_year = year - 1900; - tm.tm_wday = 0; - tm.tm_yday = 0; - tm.tm_isdst = 0; - - t = mktime(&tm); - - /* time zone adjust */ - if (t != -1) { - struct tm *gmt, keeptime2; - long delta; - time_t t2; - - if((gmt = php_gmtime_r(&t, &keeptime2))) { - tm = *gmt; /* MSVC quirks */ - } else { - return -1; /* illegal date/time */ - } - - t2 = mktime(&tm); - - /* Add the time zone diff (between the given timezone and GMT) and the - diff between the local time zone and GMT. */ - delta = (tz_offset != -1 ? tz_offset : 0) + (t - t2); - - if((delta > 0) && (t + delta < t)) { - return -1; /* time_t overflow */ - } - - t += delta; - } - - return t; -} -/* }}} */ - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ - diff --git a/http_deflatestream_object.c b/http_deflatestream_object.c deleted file mode 100644 index 6b0d472..0000000 --- a/http_deflatestream_object.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_ZLIB -#include "php_http.h" - -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_ZLIB) - -#include "php_http_api.h" -#include "php_http_encoding_api.h" -#include "php_http_exception_object.h" -#include "php_http_deflatestream_object.h" - -#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpDeflateStream, method, 0, req_args) -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpDeflateStream, method, 0) -#define HTTP_DEFLATE_ME(method, visibility) PHP_ME(HttpDeflateStream, method, HTTP_ARGS(HttpDeflateStream, method), visibility) - -HTTP_BEGIN_ARGS(__construct, 0) - HTTP_ARG_VAL(flags, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(factory, 0) - HTTP_ARG_VAL(flags, 0) - HTTP_ARG_VAL(class_name, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(update, 1) - HTTP_ARG_VAL(data, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(flush, 0) - HTTP_ARG_VAL(data, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(finish, 0) - HTTP_ARG_VAL(data, 0) -HTTP_END_ARGS; - -#define THIS_CE http_deflatestream_object_ce -zend_class_entry *http_deflatestream_object_ce; -zend_function_entry http_deflatestream_object_fe[] = { - HTTP_DEFLATE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - HTTP_DEFLATE_ME(update, ZEND_ACC_PUBLIC) - HTTP_DEFLATE_ME(flush, ZEND_ACC_PUBLIC) - HTTP_DEFLATE_ME(finish, ZEND_ACC_PUBLIC) - - HTTP_DEFLATE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - - EMPTY_FUNCTION_ENTRY -}; -static zend_object_handlers http_deflatestream_object_handlers; - -PHP_MINIT_FUNCTION(http_deflatestream_object) -{ - HTTP_REGISTER_CLASS_EX(HttpDeflateStream, http_deflatestream_object, NULL, 0); - http_deflatestream_object_handlers.clone_obj = _http_deflatestream_object_clone_obj; - -#ifndef WONKY - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_GZIP")-1, HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_ZLIB")-1, HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_RAW")-1, HTTP_DEFLATE_TYPE_RAW TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("LEVEL_DEF")-1, HTTP_DEFLATE_LEVEL_DEF TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("LEVEL_MIN")-1, HTTP_DEFLATE_LEVEL_MIN TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("LEVEL_MAX")-1, HTTP_DEFLATE_LEVEL_MAX TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_DEF")-1, HTTP_DEFLATE_STRATEGY_DEF TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_FILT")-1, HTTP_DEFLATE_STRATEGY_FILT TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_HUFF")-1, HTTP_DEFLATE_STRATEGY_HUFF TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_RLE")-1, HTTP_DEFLATE_STRATEGY_RLE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("STRATEGY_FIXED")-1, HTTP_DEFLATE_STRATEGY_FIXED TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_NONE")-1, HTTP_ENCODING_STREAM_FLUSH_NONE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_SYNC")-1, HTTP_ENCODING_STREAM_FLUSH_SYNC TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_FULL")-1, HTTP_ENCODING_STREAM_FLUSH_FULL TSRMLS_CC); -#endif - - return SUCCESS; -} - -zend_object_value _http_deflatestream_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return http_deflatestream_object_new_ex(ce, NULL, NULL); -} - -zend_object_value _http_deflatestream_object_new_ex(zend_class_entry *ce, http_encoding_stream *s, http_deflatestream_object **ptr TSRMLS_DC) -{ - zend_object_value ov; - http_deflatestream_object *o; - - o = ecalloc(1, sizeof(http_deflatestream_object)); - o->zo.ce = ce; - - if (ptr) { - *ptr = o; - } - - if (s) { - o->stream = s; - } - -#ifdef ZEND_ENGINE_2_4 - zend_object_std_init(o, ce TSRMLS_CC); - object_properties_init(o, ce); -#else - ALLOC_HASHTABLE(OBJ_PROP(o)); - zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); -#endif - - ov.handle = putObject(http_deflatestream_object, o); - ov.handlers = &http_deflatestream_object_handlers; - - return ov; -} - -zend_object_value _http_deflatestream_object_clone_obj(zval *this_ptr TSRMLS_DC) -{ - http_encoding_stream *s; - zend_object_value new_ov; - http_deflatestream_object *new_obj = NULL; - getObject(http_deflatestream_object, old_obj); - - s = ecalloc(1, sizeof(http_encoding_stream)); - s->flags = old_obj->stream->flags; - deflateCopy(&s->stream, &old_obj->stream->stream); - s->stream.opaque = phpstr_dup(s->stream.opaque); - - new_ov = http_deflatestream_object_new_ex(old_obj->zo.ce, s, &new_obj); - zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); - - return new_ov; -} - -void _http_deflatestream_object_free(zend_object *object TSRMLS_DC) -{ - http_deflatestream_object *o = (http_deflatestream_object *) object; - - if (o->stream) { - http_encoding_deflate_stream_free(&o->stream); - } - freeObject(o); -} - -/* {{{ proto void HttpDeflateStream::__construct([int flags = 0]) - Creates a new HttpDeflateStream object instance. */ -PHP_METHOD(HttpDeflateStream, __construct) -{ - long flags = 0; - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags)) { - getObject(http_deflatestream_object, obj); - - if (!obj->stream) { - obj->stream = http_encoding_deflate_stream_init(NULL, flags & 0x0fffffff); - } else { - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "HttpDeflateStream cannot be initialized twice"); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto HttpDeflateStream HttpDeflateStream::factory([int flags[, string class = "HttpDeflateStream"]]) - Creates a new HttpDeflateStream object instance. */ -PHP_METHOD(HttpDeflateStream, factory) -{ - long flags = 0; - char *cn = NULL; - int cl = 0; - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &flags, &cn, &cl)) { - zend_object_value ov; - http_encoding_stream *s = http_encoding_deflate_stream_init(NULL, flags & 0x0fffffff); - - if (SUCCESS == http_object_new(&ov, cn, cl, _http_deflatestream_object_new_ex, http_deflatestream_object_ce, s, NULL)) { - RETVAL_OBJVAL(ov, 0); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto string HttpDeflateStream::update(string data) - Passes more data through the deflate stream. */ -PHP_METHOD(HttpDeflateStream, update) -{ - int data_len; - size_t encoded_len = 0; - char *data, *encoded = NULL; - getObject(http_deflatestream_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) { - RETURN_FALSE; - } - - if (!obj->stream && !(obj->stream = http_encoding_deflate_stream_init(NULL, 0))) { - RETURN_FALSE; - } - - if (SUCCESS == http_encoding_deflate_stream_update(obj->stream, data, data_len, &encoded, &encoded_len)) { - RETURN_STRINGL(encoded, encoded_len, 0); - } else { - RETURN_FALSE; - } -} -/* }}} */ - -/* {{{ proto string HttpDeflateStream::flush([string data]) - Flushes the deflate stream. */ -PHP_METHOD(HttpDeflateStream, flush) -{ - int data_len = 0; - size_t updated_len = 0, encoded_len = 0; - char *updated = NULL, *encoded = NULL, *data = NULL; - getObject(http_deflatestream_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) { - RETURN_FALSE; - } - - if (!obj->stream && !(obj->stream = http_encoding_deflate_stream_init(NULL, 0))) { - RETURN_FALSE; - } - - if (data_len) { - if (SUCCESS != http_encoding_deflate_stream_update(obj->stream, data, data_len, &updated, &updated_len)) { - RETURN_FALSE; - } - } - - if (SUCCESS == http_encoding_deflate_stream_flush(obj->stream, &encoded, &encoded_len)) { - if (updated_len) { - updated = erealloc(updated, updated_len + encoded_len + 1); - updated[updated_len + encoded_len] = '\0'; - memcpy(updated + updated_len, encoded, encoded_len); - STR_FREE(encoded); - updated_len += encoded_len; - RETURN_STRINGL(updated, updated_len, 0); - } else if (encoded) { - RETVAL_STRINGL(encoded, encoded_len, 0); - } else { - RETVAL_NULL(); - } - } else { - RETVAL_FALSE; - } - STR_FREE(updated); -} -/* }}} */ - -/* {{{ proto string HttpDeflateStream::finish([string data]) - Finalizes the deflate stream. The deflate stream can be reused after finalizing. */ -PHP_METHOD(HttpDeflateStream, finish) -{ - int data_len = 0; - size_t updated_len = 0, encoded_len = 0; - char *updated = NULL, *encoded = NULL, *data = NULL; - getObject(http_deflatestream_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) { - RETURN_FALSE; - } - - if (!obj->stream && !(obj->stream = http_encoding_deflate_stream_init(NULL, 0))) { - RETURN_FALSE; - } - - if (data_len) { - if (SUCCESS != http_encoding_deflate_stream_update(obj->stream, data, data_len, &updated, &updated_len)) { - RETURN_FALSE; - } - } - - if (SUCCESS == http_encoding_deflate_stream_finish(obj->stream, &encoded, &encoded_len)) { - if (updated_len) { - updated = erealloc(updated, updated_len + encoded_len + 1); - updated[updated_len + encoded_len] = '\0'; - memcpy(updated + updated_len, encoded, encoded_len); - STR_FREE(encoded); - updated_len += encoded_len; - RETVAL_STRINGL(updated, updated_len, 0); - } else { - STR_FREE(updated); - RETVAL_STRINGL(encoded, encoded_len, 0); - } - } else { - STR_FREE(updated); - RETVAL_FALSE; - } - - http_encoding_deflate_stream_dtor(obj->stream); - http_encoding_deflate_stream_init(obj->stream, obj->stream->flags); -} -/* }}} */ - -#endif /* ZEND_ENGINE_2 && HTTP_HAVE_ZLIB*/ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_encoding_api.c b/http_encoding_api.c deleted file mode 100644 index 1d9b916..0000000 --- a/http_encoding_api.c +++ /dev/null @@ -1,796 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_ZLIB -#include "php_http.h" - -#include "php_http_api.h" -#include "php_http_encoding_api.h" -#include "php_http_send_api.h" -#include "php_http_headers_api.h" - -/* {{{ */ -#ifdef HTTP_HAVE_ZLIB -PHP_MINIT_FUNCTION(http_encoding) -{ - HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_DEF", HTTP_DEFLATE_LEVEL_DEF); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MIN", HTTP_DEFLATE_LEVEL_MIN); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_LEVEL_MAX", HTTP_DEFLATE_LEVEL_MAX); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_ZLIB", HTTP_DEFLATE_TYPE_ZLIB); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_GZIP", HTTP_DEFLATE_TYPE_GZIP); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_TYPE_RAW", HTTP_DEFLATE_TYPE_RAW); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_DEF", HTTP_DEFLATE_STRATEGY_DEF); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FILT", HTTP_DEFLATE_STRATEGY_FILT); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_HUFF", HTTP_DEFLATE_STRATEGY_HUFF); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_RLE", HTTP_DEFLATE_STRATEGY_RLE); - HTTP_LONG_CONSTANT("HTTP_DEFLATE_STRATEGY_FIXED", HTTP_DEFLATE_STRATEGY_FIXED); - - HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_NONE", HTTP_ENCODING_STREAM_FLUSH_NONE); - HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_SYNC", HTTP_ENCODING_STREAM_FLUSH_SYNC); - HTTP_LONG_CONSTANT("HTTP_ENCODING_STREAM_FLUSH_FULL", HTTP_ENCODING_STREAM_FLUSH_FULL); - - return SUCCESS; -} - -PHP_RINIT_FUNCTION(http_encoding) -{ - if (HTTP_G->send.inflate.start_auto) { -#ifdef PHP_OUTPUT_NEWAPI - php_output_start_internal(ZEND_STRL("http inflate"), _http_ob_inflatehandler, HTTP_INFLATE_BUFFER_SIZE, 0 TSRMLS_CC); -#else - php_ob_set_internal_handler(_http_ob_inflatehandler, HTTP_INFLATE_BUFFER_SIZE, "http inflate", 0 TSRMLS_CC); -#endif - } - if (HTTP_G->send.deflate.start_auto) { -#ifdef PHP_OUTPUT_NEWAPI - php_output_start_internal(ZEND_STRL("http deflate"), _http_ob_deflatehandler, HTTP_DEFLATE_BUFFER_SIZE, 0 TSRMLS_CC); -#else - php_ob_set_internal_handler(_http_ob_deflatehandler, HTTP_DEFLATE_BUFFER_SIZE, "http deflate", 0 TSRMLS_CC); -#endif - } - return SUCCESS; -} - -PHP_RSHUTDOWN_FUNCTION(http_encoding) -{ - if (HTTP_G->send.deflate.stream) { - http_encoding_deflate_stream_free((http_encoding_stream **) &HTTP_G->send.deflate.stream); - } - if (HTTP_G->send.inflate.stream) { - http_encoding_inflate_stream_free((http_encoding_stream **) &HTTP_G->send.inflate.stream); - } - return SUCCESS; -} -#endif -/* }}} */ - -/* {{{ eol_match(char **, int *) */ -static inline int eol_match(char **line, int *eol_len) -{ - char *ptr = *line; - - while (' ' == *ptr) ++ptr; - - if (ptr == http_locate_eol(*line, eol_len)) { - *line = ptr; - return 1; - } else { - return 0; - } -} -/* }}} */ - -/* {{{ char *http_encoding_dechunk(char *, size_t, char **, size_t *) */ -PHP_HTTP_API const char *_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC) -{ - int eol_len = 0; - char *n_ptr = NULL; - const char *e_ptr = encoded; - - *decoded_len = 0; - *decoded = ecalloc(1, encoded_len); - - while ((encoded + encoded_len - e_ptr) > 0) { - ulong chunk_len = 0, rest; - - chunk_len = strtoul(e_ptr, &n_ptr, 16); - - /* we could not read in chunk size */ - if (n_ptr == e_ptr) { - /* - * if this is the first turn and there doesn't seem to be a chunk - * size at the begining of the body, do not fail on apparently - * not encoded data and return a copy - */ - if (e_ptr == encoded) { - http_error(HE_NOTICE, HTTP_E_ENCODING, "Data does not seem to be chunked encoded"); - memcpy(*decoded, encoded, encoded_len); - *decoded_len = encoded_len; - return encoded + encoded_len; - } else { - efree(*decoded); - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Expected chunk size at pos %tu of %zu but got trash", n_ptr - encoded, encoded_len); - return NULL; - } - } - - /* reached the end */ - if (!chunk_len) { - /* move over '0' chunked encoding terminator */ - while (*e_ptr == '0') ++e_ptr; - break; - } - - /* there should be CRLF after the chunk size, but we'll ignore SP+ too */ - if (*n_ptr && !eol_match(&n_ptr, &eol_len)) { - if (eol_len == 2) { - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Expected CRLF at pos %tu of %zu but got 0x%02X 0x%02X", n_ptr - encoded, encoded_len, *n_ptr, *(n_ptr + 1)); - } else { - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr - encoded, encoded_len, *n_ptr); - } - } - n_ptr += eol_len; - - /* chunk size pretends more data than we actually got, so it's probably a truncated message */ - if (chunk_len > (rest = encoded + encoded_len - n_ptr)) { - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Truncated message: chunk size %lu exceeds remaining data size %lu at pos %tu of %zu", chunk_len, rest, n_ptr - encoded, encoded_len); - chunk_len = rest; - } - - /* copy the chunk */ - memcpy(*decoded + *decoded_len, n_ptr, chunk_len); - *decoded_len += chunk_len; - - if (chunk_len == rest) { - e_ptr = n_ptr + chunk_len; - break; - } else { - /* advance to next chunk */ - e_ptr = n_ptr + chunk_len + eol_len; - } - } - - return e_ptr; -} -/* }}} */ - -/* {{{ int http_encoding_response_start(size_t) */ -PHP_HTTP_API int _http_encoding_response_start(size_t content_length, zend_bool ignore_http_ohandler TSRMLS_DC) -{ - int response = HTTP_G->send.deflate.response; -#ifdef PHP_OUTPUT_NEWAPI - int ohandler = php_output_handler_started(ZEND_STRL("ob_gzhandler") TSRMLS_CC) || php_output_handler_started(ZEND_STRL("zlib output compression") TSRMLS_CC); -#else - int ohandler = php_ob_handler_used("ob_gzhandler" TSRMLS_CC) || php_ob_handler_used("zlib output compression" TSRMLS_CC); -#endif - - if (!ohandler && !ignore_http_ohandler) { -#ifdef PHP_OUTPUT_NEWAPI - ohandler = php_output_handler_started(ZEND_STRL("ob_defaltehandler") TSRMLS_CC) || php_output_handler_started(ZEND_STRL("http deflate") TSRMLS_CC); -#else - ohandler = php_ob_handler_used("ob_deflatehandler" TSRMLS_CC) || php_ob_handler_used("http deflate" TSRMLS_CC); -#endif - } - - if (response && !ohandler) { -#ifdef HTTP_HAVE_ZLIB - HashTable *selected; - zval zsupported; - - HTTP_G->send.deflate.encoding = 0; - - INIT_PZVAL(&zsupported); - array_init(&zsupported); - add_next_index_stringl(&zsupported, "gzip", lenof("gzip"), 1); - add_next_index_stringl(&zsupported, "x-gzip", lenof("x-gzip"), 1); - add_next_index_stringl(&zsupported, "deflate", lenof("deflate"), 1); - - if ((selected = http_negotiate_encoding(&zsupported))) { - STATUS hs = FAILURE; - char *encoding = NULL; - ulong idx; - - if (HASH_KEY_IS_STRING == zend_hash_get_current_key(selected, &encoding, &idx, 0) && encoding) { - if (!strcmp(encoding, "gzip") || !strcmp(encoding, "x-gzip")) { - if (SUCCESS == (hs = http_send_header_string("Content-Encoding: gzip"))) { - HTTP_G->send.deflate.encoding = HTTP_ENCODING_GZIP; - } - } else if (!strcmp(encoding, "deflate")) { - if (SUCCESS == (hs = http_send_header_string("Content-Encoding: deflate"))) { - HTTP_G->send.deflate.encoding = HTTP_ENCODING_DEFLATE; - } - } - if (SUCCESS == hs) { - http_send_header_string("Vary: Accept-Encoding"); - } - } - - zend_hash_destroy(selected); - FREE_HASHTABLE(selected); - } - - zval_dtor(&zsupported); -#else - HTTP_G->send.deflate.encoding = 0; - php_start_ob_buffer_named("ob_gzhandler", 0, 0 TSRMLS_CC); -#endif /* HTTP_HAVE_ZLIB */ - } else if (content_length && !ohandler) { - /* emit a content-length header */ - phpstr header; - - phpstr_init(&header); - phpstr_appendf(&header, "Content-Length: %zu", content_length); - phpstr_fix(&header); - http_send_header_string_ex(PHPSTR_VAL(&header), PHPSTR_LEN(&header), 1); - phpstr_dtor(&header); - } else { - HTTP_G->send.deflate.encoding = 0; - } - - return HTTP_G->send.deflate.encoding; -} -/* }}} */ - -#ifdef HTTP_HAVE_ZLIB - -/* {{{ inline int http_inflate_rounds */ -static inline int http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len) -{ - int status = 0, round = 0; - phpstr buffer; - - *buf = NULL; - *len = 0; - - phpstr_init_ex(&buffer, Z->avail_in, PHPSTR_INIT_PREALLOC); - - do { - if (PHPSTR_NOMEM == phpstr_resize_ex(&buffer, buffer.size, 0, 1)) { - status = Z_MEM_ERROR; - } else { - Z->avail_out = buffer.free; - Z->next_out = (Bytef *) buffer.data + buffer.used; -#if 0 - fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out); -#endif - status = inflate(Z, flush); - - buffer.used += buffer.free - Z->avail_out; - buffer.free = Z->avail_out; -#if 0 - fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out); -#endif - HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size); - } - } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < HTTP_INFLATE_ROUNDS); - - if (status == Z_OK || status == Z_STREAM_END) { - phpstr_shrink(&buffer); - phpstr_fix(&buffer); - *buf = buffer.data; - *len = buffer.used; - } else { - phpstr_dtor(&buffer); - } - - return status; -} -/* }}} */ - -/* {{{ STATUS http_encoding_deflate(int, char *, size_t, char **, size_t *) */ -PHP_HTTP_API STATUS _http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - int status, level, wbits, strategy; - z_stream Z; - - HTTP_DEFLATE_LEVEL_SET(flags, level); - HTTP_DEFLATE_WBITS_SET(flags, wbits); - HTTP_DEFLATE_STRATEGY_SET(flags, strategy); - - memset(&Z, 0, sizeof(z_stream)); - *encoded = NULL; - *encoded_len = 0; - - status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy); - if (Z_OK == status) { - *encoded_len = HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len); - *encoded = emalloc_rel(*encoded_len); - - Z.next_in = (Bytef *) data; - Z.next_out = (Bytef *) *encoded; - Z.avail_in = data_len; - Z.avail_out = *encoded_len; - - status = deflate(&Z, Z_FINISH); - deflateEnd(&Z); - - if (Z_STREAM_END == status) { - /* size buffer down to actual length */ - *encoded = erealloc_rel(*encoded, Z.total_out + 1); - (*encoded)[*encoded_len = Z.total_out] = '\0'; - return SUCCESS; - } else { - STR_SET(*encoded, NULL); - *encoded_len = 0; - } - } - - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not deflate data: %s", zError(status)); - return FAILURE; -} -/* }}} */ - -/* {{{ STATUS http_encoding_inflate(char *, size_t, char **, size_t) */ -PHP_HTTP_API STATUS _http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - z_stream Z; - int status, wbits = HTTP_WINDOW_BITS_ANY; - - memset(&Z, 0, sizeof(z_stream)); - -retry_raw_inflate: - status = inflateInit2(&Z, wbits); - if (Z_OK == status) { - Z.next_in = (Bytef *) data; - Z.avail_in = data_len; - - switch (status = http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) { - case Z_STREAM_END: - inflateEnd(&Z); - return SUCCESS; - - case Z_OK: - status = Z_DATA_ERROR; - break; - - case Z_DATA_ERROR: - /* raw deflated data? */ - if (HTTP_WINDOW_BITS_ANY == wbits) { - inflateEnd(&Z); - wbits = HTTP_WINDOW_BITS_RAW; - goto retry_raw_inflate; - } - } - inflateEnd(&Z); - } - - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not inflate data: %s", zError(status)); - return FAILURE; -} -/* }}} */ - -/* {{{ http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *, int) */ -PHP_HTTP_API http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - int status, level, wbits, strategy, free_stream; - - if ((free_stream = !s)) { - s = pemalloc_rel(sizeof(http_encoding_stream), (flags & HTTP_ENCODING_STREAM_PERSISTENT)); - } - memset(s, 0, sizeof(http_encoding_stream)); - s->flags = flags; - - HTTP_DEFLATE_LEVEL_SET(flags, level); - HTTP_DEFLATE_WBITS_SET(flags, wbits); - HTTP_DEFLATE_STRATEGY_SET(flags, strategy); - - if (Z_OK == (status = deflateInit2(&s->stream, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy))) { - int p = (flags & HTTP_ENCODING_STREAM_PERSISTENT) ? PHPSTR_INIT_PERSISTENT:0; - - if ((s->stream.opaque = phpstr_init_ex(NULL, HTTP_DEFLATE_BUFFER_SIZE, p))) { - return s; - } - deflateEnd(&s->stream); - status = Z_MEM_ERROR; - } - - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to initialize deflate encoding stream: %s", zError(status)); - if (free_stream) { - efree(s); - } - return NULL; -} -/* }}} */ - -/* {{{ http_encoding_stream *http_encoding_inflate_stream_init(http_encoding_stream *, int) */ -PHP_HTTP_API http_encoding_stream *_http_encoding_inflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - int status, wbits, free_stream; - - if ((free_stream = !s)) { - s = pemalloc_rel(sizeof(http_encoding_stream), (flags & HTTP_ENCODING_STREAM_PERSISTENT)); - } - memset(s, 0, sizeof(http_encoding_stream)); - s->flags = flags; - - HTTP_INFLATE_WBITS_SET(flags, wbits); - - if (Z_OK == (status = inflateInit2(&s->stream, wbits))) { - int p = (flags & HTTP_ENCODING_STREAM_PERSISTENT) ? PHPSTR_INIT_PERSISTENT:0; - - if ((s->stream.opaque = phpstr_init_ex(NULL, HTTP_DEFLATE_BUFFER_SIZE, p))) { - return s; - } - inflateEnd(&s->stream); - status = Z_MEM_ERROR; - } - - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to initialize inflate stream: %s", zError(status)); - if (free_stream) { - efree(s); - } - return NULL; -} -/* }}} */ - -/* {{{ STATUS http_encoding_deflate_stream_update(http_encoding_stream *, char *, size_t, char **, size_t *) */ -PHP_HTTP_API STATUS _http_encoding_deflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - int status; - - /* append input to our buffer */ - phpstr_append(PHPSTR(s->stream.opaque), data, data_len); - - s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque); - s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); - - /* deflate */ - *encoded_len = HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len); - *encoded = emalloc_rel(*encoded_len); - s->stream.avail_out = *encoded_len; - s->stream.next_out = (Bytef *) *encoded; - - switch (status = deflate(&s->stream, HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags))) { - case Z_OK: - case Z_STREAM_END: - /* cut processed chunk off the buffer */ - if (s->stream.avail_in) { - phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in); - } else { - phpstr_reset(PHPSTR(s->stream.opaque)); - } - - /* size buffer down to actual size */ - *encoded_len -= s->stream.avail_out; - *encoded = erealloc_rel(*encoded, *encoded_len + 1); - (*encoded)[*encoded_len] = '\0'; - return SUCCESS; - } - - STR_SET(*encoded, NULL); - *encoded_len = 0; - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to update deflate stream: %s", zError(status)); - return FAILURE; -} -/* }}} */ - -/* {{{ STATUS http_encoding_inflate_stream_update(http_encoding_stream *, char *, size_t, char **, size_t *) */ -PHP_HTTP_API STATUS _http_encoding_inflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - int status; - - /* append input to buffer */ - phpstr_append(PHPSTR(s->stream.opaque), data, data_len); - -retry_raw_inflate: - s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque); - s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); - - switch (status = http_inflate_rounds(&s->stream, HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags), decoded, decoded_len)) { - case Z_OK: - case Z_STREAM_END: - /* cut off */ - if (s->stream.avail_in) { - phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in); - } else { - phpstr_reset(PHPSTR(s->stream.opaque)); - } - return SUCCESS; - - case Z_DATA_ERROR: - /* raw deflated data ? */ - if (!(s->flags & HTTP_INFLATE_TYPE_RAW) && !s->stream.total_out) { - inflateEnd(&s->stream); - s->flags |= HTTP_INFLATE_TYPE_RAW; - inflateInit2(&s->stream, HTTP_WINDOW_BITS_RAW); - goto retry_raw_inflate; - } - } - - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to update inflate stream: %s", zError(status)); - return FAILURE; -} -/* }}} */ - -/* {{{ STATUS http_encoding_deflate_stream_flush(http_encoding_stream *, char **, size_t *) */ -PHP_HTTP_API STATUS _http_encoding_deflate_stream_flush(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - int status; - - *encoded_len = HTTP_DEFLATE_BUFFER_SIZE; - *encoded = emalloc_rel(*encoded_len); - - s->stream.avail_in = 0; - s->stream.next_in = NULL; - s->stream.avail_out = *encoded_len; - s->stream.next_out = (Bytef *) *encoded; - - switch (status = deflate(&s->stream, Z_FULL_FLUSH)) { - case Z_OK: - case Z_STREAM_END: - *encoded_len = HTTP_DEFLATE_BUFFER_SIZE - s->stream.avail_out; - *encoded = erealloc_rel(*encoded, *encoded_len + 1); - (*encoded)[*encoded_len] = '\0'; - return SUCCESS; - } - - STR_SET(*encoded, NULL); - *encoded_len = 0; - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to flush deflate stream: %s", zError(status)); - return FAILURE; -} -/* }}} */ - -/* {{{ STATUS http_encoding_inflate_straem_flush(http_encoding_stream *, char **, size_t *) */ -PHP_HTTP_API STATUS _http_encoding_inflate_stream_flush(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - /* noop */ - *decoded = estrndup("", *decoded_len = 0); - return SUCCESS; -} -/* }}} */ - -/* {{{ STATUS http_encoding_deflate_stream_finish(http_encoding_stream *, char **, size_t *) */ -PHP_HTTP_API STATUS _http_encoding_deflate_stream_finish(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - int status; - - *encoded_len = HTTP_DEFLATE_BUFFER_SIZE; - *encoded = emalloc_rel(*encoded_len); - - /* deflate remaining input */ - s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque); - s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); - - s->stream.avail_out = *encoded_len; - s->stream.next_out = (Bytef *) *encoded; - - do { - status = deflate(&s->stream, Z_FINISH); - } while (Z_OK == status); - - if (Z_STREAM_END == status) { - /* cut processed intp off */ - phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in); - - /* size down */ - *encoded_len -= s->stream.avail_out; - *encoded = erealloc_rel(*encoded, *encoded_len + 1); - (*encoded)[*encoded_len] = '\0'; - return SUCCESS; - } - - STR_SET(*encoded, NULL); - *encoded_len = 0; - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to finish deflate stream: %s", zError(status)); - return FAILURE; -} -/* }}} */ - -/* {{{ STATUS http_encoding_inflate_stream_finish(http_encoding_stream *, char **, size_t *) */ -PHP_HTTP_API STATUS _http_encoding_inflate_stream_finish(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - int status; - - if (!PHPSTR_LEN(s->stream.opaque)) { - *decoded = NULL; - *decoded_len = 0; - return SUCCESS; - } - - *decoded_len = (PHPSTR_LEN(s->stream.opaque) + 1) * HTTP_INFLATE_ROUNDS; - *decoded = emalloc_rel(*decoded_len); - - /* inflate remaining input */ - s->stream.next_in = (Bytef *) PHPSTR_VAL(s->stream.opaque); - s->stream.avail_in = PHPSTR_LEN(s->stream.opaque); - - s->stream.avail_out = *decoded_len; - s->stream.next_out = (Bytef *) *decoded; - - if (Z_STREAM_END == (status = inflate(&s->stream, Z_FINISH))) { - /* cut processed input off */ - phpstr_cut(PHPSTR(s->stream.opaque), 0, PHPSTR_LEN(s->stream.opaque) - s->stream.avail_in); - - /* size down */ - *decoded_len -= s->stream.avail_out; - *decoded = erealloc_rel(*decoded, *decoded_len + 1); - (*decoded)[*decoded_len] = '\0'; - return SUCCESS; - } - - STR_SET(*decoded, NULL); - *decoded_len = 0; - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Failed to finish inflate stream: %s", zError(status)); - return FAILURE; -} -/* }}} */ - -/* {{{ void http_encoding_deflate_stream_dtor(http_encoding_stream *) */ -PHP_HTTP_API void _http_encoding_deflate_stream_dtor(http_encoding_stream *s TSRMLS_DC) -{ - if (s) { - if (s->stream.opaque) { - phpstr_free((phpstr **) &s->stream.opaque); - } - deflateEnd(&s->stream); - } -} -/* }}} */ - -/* {{{ void http_encoding_inflate_stream_dtor(http_encoding_stream *) */ -PHP_HTTP_API void _http_encoding_inflate_stream_dtor(http_encoding_stream *s TSRMLS_DC) -{ - if (s) { - if (s->stream.opaque) { - phpstr_free((phpstr **) &s->stream.opaque); - } - inflateEnd(&s->stream); - } -} -/* }}} */ - -/* {{{ void http_encoding_deflate_stream_free(http_encoding_stream **) */ -PHP_HTTP_API void _http_encoding_deflate_stream_free(http_encoding_stream **s TSRMLS_DC) -{ - if (s) { - http_encoding_deflate_stream_dtor(*s); - if (*s) { - pefree(*s, (*s)->flags & HTTP_ENCODING_STREAM_PERSISTENT); - } - *s = NULL; - } -} -/* }}} */ - -/* {{{ void http_encoding_inflate_stream_free(http_encoding_stream **) */ -PHP_HTTP_API void _http_encoding_inflate_stream_free(http_encoding_stream **s TSRMLS_DC) -{ - if (s) { - http_encoding_inflate_stream_dtor(*s); - if (*s) { - pefree(*s, (*s)->flags & HTTP_ENCODING_STREAM_PERSISTENT); - } - *s = NULL; - } -} -/* }}} */ - -/* {{{ void http_ob_deflatehandler(char *, uint, char **, uint *, int) */ -void _http_ob_deflatehandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC) -{ - int encoding; - - *handled_output = NULL; - *handled_output_len = 0; - - if (mode & PHP_OUTPUT_HANDLER_START) { - int flags; - - if (HTTP_G->send.deflate.stream) { - zend_error(E_ERROR, "ob_deflatehandler() can only be used once"); - return; - } - - HTTP_G->send.deflate.response = 1; - encoding = http_encoding_response_start(0, 1); - HTTP_G->send.deflate.response = 0; - - switch (encoding) { - case HTTP_ENCODING_GZIP: - flags = HTTP_DEFLATE_TYPE_GZIP; - break; - - case HTTP_ENCODING_DEFLATE: - flags = HTTP_DEFLATE_TYPE_ZLIB; - break; - - default: - goto deflate_passthru_plain; - } - - flags |= (HTTP_G->send.deflate.start_flags &~ 0xf0); - HTTP_G->send.deflate.stream = http_encoding_deflate_stream_init(NULL, flags); - } - - if (HTTP_G->send.deflate.stream) { - if (output_len) { - size_t tmp_len; - - http_encoding_deflate_stream_update((http_encoding_stream *) HTTP_G->send.deflate.stream, output, output_len, handled_output, &tmp_len); - *handled_output_len = tmp_len; - } - - if (mode & PHP_OUTPUT_HANDLER_END) { - char *remaining = NULL; - size_t remaining_len = 0; - - http_encoding_deflate_stream_finish((http_encoding_stream *) HTTP_G->send.deflate.stream, &remaining, &remaining_len); - http_encoding_deflate_stream_free((http_encoding_stream **) &HTTP_G->send.deflate.stream); - if (remaining) { - *handled_output = erealloc(*handled_output, *handled_output_len + remaining_len + 1); - memcpy(*handled_output + *handled_output_len, remaining, remaining_len); - (*handled_output)[*handled_output_len += remaining_len] = '\0'; - efree(remaining); - } - } - } else { -deflate_passthru_plain: - *handled_output = estrndup(output, *handled_output_len = output_len); - } -} -/* }}} */ - -/* {{{ void http_ob_inflatehandler(char *, uint, char **, uint *, int) */ -void _http_ob_inflatehandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC) -{ - *handled_output = NULL; - *handled_output_len = 0; - - if (mode & PHP_OUTPUT_HANDLER_START) { - if (HTTP_G->send.inflate.stream) { - zend_error(E_ERROR, "ob_inflatehandler() can only be used once"); - return; - } - HTTP_G->send.inflate.stream = http_encoding_inflate_stream_init(NULL, (HTTP_G->send.inflate.start_flags &~ 0xf0)); - } - - if (HTTP_G->send.inflate.stream) { - if (output_len) { - size_t tmp_len; - - http_encoding_inflate_stream_update((http_encoding_stream *) HTTP_G->send.inflate.stream, output, output_len, handled_output, &tmp_len); - *handled_output_len = tmp_len; - } - - if (mode & PHP_OUTPUT_HANDLER_END) { - char *remaining = NULL; - size_t remaining_len = 0; - - http_encoding_inflate_stream_finish((http_encoding_stream *) HTTP_G->send.inflate.stream, &remaining, &remaining_len); - http_encoding_inflate_stream_free((http_encoding_stream **) &HTTP_G->send.inflate.stream); - if (remaining) { - *handled_output = erealloc(*handled_output, *handled_output_len + remaining_len + 1); - memcpy(*handled_output + *handled_output_len, remaining, remaining_len); - (*handled_output)[*handled_output_len += remaining_len] = '\0'; - efree(remaining); - } - } - } else { - *handled_output = estrndup(output, *handled_output_len = output_len); - } -} -/* }}} */ - -#endif /* HTTP_HAVE_ZLIB */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_exception_object.c b/http_exception_object.c deleted file mode 100644 index c883863..0000000 --- a/http_exception_object.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "php_http.h" - -#ifdef ZEND_ENGINE_2 - -#ifndef HTTP_DBG_EXCEPTIONS -# define HTTP_DBG_EXCEPTIONS 0 -#endif - -#include "zend_interfaces.h" -#include "zend_exceptions.h" -#include "php_http_exception_object.h" - -zend_class_entry *http_exception_object_ce; -zend_class_entry *HTTP_EX_CE(runtime); -zend_class_entry *HTTP_EX_CE(header); -zend_class_entry *HTTP_EX_CE(malformed_headers); -zend_class_entry *HTTP_EX_CE(request_method); -zend_class_entry *HTTP_EX_CE(message_type); -zend_class_entry *HTTP_EX_CE(invalid_param); -zend_class_entry *HTTP_EX_CE(encoding); -zend_class_entry *HTTP_EX_CE(request); -zend_class_entry *HTTP_EX_CE(request_pool); -zend_class_entry *HTTP_EX_CE(socket); -zend_class_entry *HTTP_EX_CE(response); -zend_class_entry *HTTP_EX_CE(url); -zend_class_entry *HTTP_EX_CE(querystring); - -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpException, method, 0) -#define HTTP_EXCEPTION_ME(method, visibility) PHP_ME(HttpException, method, HTTP_ARGS(HttpException, method), visibility) - -HTTP_EMPTY_ARGS(__toString); - -zend_function_entry http_exception_object_fe[] = { - HTTP_EXCEPTION_ME(__toString, ZEND_ACC_PUBLIC) - - EMPTY_FUNCTION_ENTRY -}; - -#if HTTP_DBG_EXCEPTIONS -static void http_exception_hook(zval *ex TSRMLS_DC) -{ - if (ex) { - zval *m = zend_read_property(Z_OBJCE_P(ex), ex, "message", lenof("message"), 0 TSRMLS_CC); - fprintf(stderr, "*** Threw exception '%s'\n", Z_STRVAL_P(m)); - } else { - fprintf(stderr, "*** Threw NULL exception\n"); - } -} -#endif - -PHP_MINIT_FUNCTION(http_exception_object) -{ - HTTP_REGISTER_CLASS(HttpException, http_exception_object, ZEND_EXCEPTION_GET_DEFAULT(), 0); - - zend_declare_property_null(HTTP_EX_DEF_CE, "innerException", lenof("innerException"), ZEND_ACC_PUBLIC TSRMLS_CC); - - HTTP_REGISTER_EXCEPTION(HttpRuntimeException, HTTP_EX_CE(runtime), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpInvalidParamException, HTTP_EX_CE(invalid_param), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpHeaderException, HTTP_EX_CE(header), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpMalformedHeadersException, HTTP_EX_CE(malformed_headers), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpRequestMethodException, HTTP_EX_CE(request_method), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpMessageTypeException, HTTP_EX_CE(message_type), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpEncodingException, HTTP_EX_CE(encoding), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpRequestException, HTTP_EX_CE(request), HTTP_EX_DEF_CE); - - zend_declare_property_long(HTTP_EX_CE(request), "curlCode", lenof("curlCode"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); - - HTTP_REGISTER_EXCEPTION(HttpRequestPoolException, HTTP_EX_CE(request_pool), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpSocketException, HTTP_EX_CE(socket), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpResponseException, HTTP_EX_CE(response), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpUrlException, HTTP_EX_CE(url), HTTP_EX_DEF_CE); - HTTP_REGISTER_EXCEPTION(HttpQueryStringException, HTTP_EX_CE(querystring), HTTP_EX_DEF_CE); - - HTTP_LONG_CONSTANT("HTTP_E_RUNTIME", HTTP_E_RUNTIME); - HTTP_LONG_CONSTANT("HTTP_E_INVALID_PARAM", HTTP_E_INVALID_PARAM); - HTTP_LONG_CONSTANT("HTTP_E_HEADER", HTTP_E_HEADER); - HTTP_LONG_CONSTANT("HTTP_E_MALFORMED_HEADERS", HTTP_E_MALFORMED_HEADERS); - HTTP_LONG_CONSTANT("HTTP_E_REQUEST_METHOD", HTTP_E_REQUEST_METHOD); - HTTP_LONG_CONSTANT("HTTP_E_MESSAGE_TYPE", HTTP_E_MESSAGE_TYPE); - HTTP_LONG_CONSTANT("HTTP_E_ENCODING", HTTP_E_ENCODING); - HTTP_LONG_CONSTANT("HTTP_E_REQUEST", HTTP_E_REQUEST); - HTTP_LONG_CONSTANT("HTTP_E_REQUEST_POOL", HTTP_E_REQUEST_POOL); - HTTP_LONG_CONSTANT("HTTP_E_SOCKET", HTTP_E_SOCKET); - HTTP_LONG_CONSTANT("HTTP_E_RESPONSE", HTTP_E_RESPONSE); - HTTP_LONG_CONSTANT("HTTP_E_URL", HTTP_E_URL); - HTTP_LONG_CONSTANT("HTTP_E_QUERYSTRING", HTTP_E_QUERYSTRING); - -#if HTTP_DBG_EXCEPTIONS - zend_throw_exception_hook=http_exception_hook; -#endif - - return SUCCESS; -} - -zend_class_entry *_http_exception_get_default() -{ - return http_exception_object_ce; -} - -zend_class_entry *_http_exception_get_for_code(long code) -{ - zend_class_entry *ex = http_exception_object_ce; - - switch (code) { - case HTTP_E_RUNTIME: ex = HTTP_EX_CE(runtime); break; - case HTTP_E_INVALID_PARAM: ex = HTTP_EX_CE(invalid_param); break; - case HTTP_E_HEADER: ex = HTTP_EX_CE(header); break; - case HTTP_E_MALFORMED_HEADERS: ex = HTTP_EX_CE(malformed_headers); break; - case HTTP_E_REQUEST_METHOD: ex = HTTP_EX_CE(request_method); break; - case HTTP_E_MESSAGE_TYPE: ex = HTTP_EX_CE(message_type); break; - case HTTP_E_ENCODING: ex = HTTP_EX_CE(encoding); break; - case HTTP_E_REQUEST: ex = HTTP_EX_CE(request); break; - case HTTP_E_REQUEST_POOL: ex = HTTP_EX_CE(request_pool); break; - case HTTP_E_SOCKET: ex = HTTP_EX_CE(socket); break; - case HTTP_E_RESPONSE: ex = HTTP_EX_CE(response); break; - case HTTP_E_URL: ex = HTTP_EX_CE(url); break; - case HTTP_E_QUERYSTRING: ex = HTTP_EX_CE(querystring); break; - } - - return ex; -} - -PHP_METHOD(HttpException, __toString) -{ - phpstr full_str; - zend_class_entry *ce; - zval *zobj = getThis(), *retval = NULL, *m, *f, *l; - - phpstr_init(&full_str); - - do { - ce = Z_OBJCE_P(zobj); - - m = zend_read_property(ce, zobj, "message", lenof("message"), 0 TSRMLS_CC); - f = zend_read_property(ce, zobj, "file", lenof("file"), 0 TSRMLS_CC); - l = zend_read_property(ce, zobj, "line", lenof("line"), 0 TSRMLS_CC); - - if (m && f && l && Z_TYPE_P(m) == IS_STRING && Z_TYPE_P(f) == IS_STRING && Z_TYPE_P(l) == IS_LONG) { - if (zobj != getThis()) { - phpstr_appends(&full_str, " inner "); - } - - phpstr_appendf(&full_str, "exception '%.*s' with message '%.*s' in %.*s:%ld" PHP_EOL, - ce->name_length, ce->name, Z_STRLEN_P(m), Z_STRVAL_P(m), Z_STRLEN_P(f), Z_STRVAL_P(f), Z_LVAL_P(l) - ); - } else { - break; - } - - zobj = zend_read_property(ce, zobj, "innerException", lenof("innerException"), 0 TSRMLS_CC); - } while (Z_TYPE_P(zobj) == IS_OBJECT); - - if (zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "gettraceasstring", &retval) && Z_TYPE_P(retval) == IS_STRING) { - phpstr_appends(&full_str, "Stack trace:" PHP_EOL); - phpstr_append(&full_str, Z_STRVAL_P(retval), Z_STRLEN_P(retval)); - zval_ptr_dtor(&retval); - } - - RETURN_PHPSTR_VAL(&full_str); -} - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_filter_api.c b/http_filter_api.c deleted file mode 100644 index 23b7119..0000000 --- a/http_filter_api.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_ZLIB -#include "php_http.h" - -#ifdef ZEND_ENGINE_2 - -#include "php_streams.h" -#include "php_http_api.h" -#include "php_http_encoding_api.h" -#include "php_http_filter_api.h" - -PHP_MINIT_FUNCTION(http_filter) -{ - php_stream_filter_register_factory("http.*", &http_filter_factory TSRMLS_CC); - return SUCCESS; -} - -/* - - -*/ - -#define HTTP_FILTER_PARAMS \ - php_stream *stream, \ - php_stream_filter *this, \ - php_stream_bucket_brigade *buckets_in, \ - php_stream_bucket_brigade *buckets_out, \ - size_t *bytes_consumed, int flags \ - TSRMLS_DC -#define HTTP_FILTER_OP(filter) \ - http_filter_op_ ##filter -#define HTTP_FILTER_OPS(filter) \ - php_stream_filter_ops HTTP_FILTER_OP(filter) -#define HTTP_FILTER_DTOR(filter) \ - http_filter_ ##filter## _dtor -#define HTTP_FILTER_DESTRUCTOR(filter) \ - void HTTP_FILTER_DTOR(filter)(php_stream_filter *this TSRMLS_DC) -#define HTTP_FILTER_FUNC(filter) \ - http_filter_ ##filter -#define HTTP_FILTER_FUNCTION(filter) \ - php_stream_filter_status_t HTTP_FILTER_FUNC(filter)(HTTP_FILTER_PARAMS) -#define HTTP_FILTER_BUFFER(filter) \ - http_filter_ ##filter## _buffer - -#define NEW_BUCKET(data, length) \ - { \ - char *__data; \ - php_stream_bucket *__buck; \ - \ - __data = pemalloc(length, this->is_persistent); \ - if (!__data) { \ - return PSFS_ERR_FATAL; \ - } \ - memcpy(__data, data, length); \ - \ - __buck = php_stream_bucket_new(stream, __data, length, 1, this->is_persistent TSRMLS_CC); \ - if (!__buck) { \ - pefree(__data, this->is_persistent); \ - return PSFS_ERR_FATAL; \ - } \ - \ - php_stream_bucket_append(buckets_out, __buck TSRMLS_CC); \ - } - -typedef struct _http_chunked_decode_filter_buffer_t { - phpstr buffer; - ulong hexlen; -} HTTP_FILTER_BUFFER(chunked_decode); - -#ifdef HTTP_HAVE_ZLIB -typedef http_encoding_stream HTTP_FILTER_BUFFER(deflate); -typedef http_encoding_stream HTTP_FILTER_BUFFER(inflate); -#endif /* HTTP_HAVE_ZLIB */ - - -static HTTP_FILTER_FUNCTION(chunked_decode) -{ - int out_avail = 0; - php_stream_bucket *ptr, *nxt; - HTTP_FILTER_BUFFER(chunked_decode) *buffer = (HTTP_FILTER_BUFFER(chunked_decode) *) (this->abstract); - - if (bytes_consumed) { - *bytes_consumed = 0; - } - - /* new data available? */ - if (buckets_in->head) { - - /* fetch available bucket data */ - for (ptr = buckets_in->head; ptr; ptr = nxt) { - nxt = ptr->next; - if (bytes_consumed) { - *bytes_consumed += ptr->buflen; - } - - if (PHPSTR_NOMEM == phpstr_append(PHPSTR(buffer), ptr->buf, ptr->buflen)) { - return PSFS_ERR_FATAL; - } - - php_stream_bucket_unlink(ptr TSRMLS_CC); - php_stream_bucket_delref(ptr TSRMLS_CC); - } - } - if (!phpstr_fix(PHPSTR(buffer))) { - return PSFS_ERR_FATAL; - } - - /* we have data in our buffer */ - while (PHPSTR_LEN(buffer)) { - - /* we already know the size of the chunk and are waiting for data */ - if (buffer->hexlen) { - - /* not enough data buffered */ - if (PHPSTR_LEN(buffer) < buffer->hexlen) { - - /* flush anyway? */ - if (flags & PSFS_FLAG_FLUSH_INC) { - - /* flush all data (should only be chunk data) */ - out_avail = 1; - NEW_BUCKET(PHPSTR_VAL(buffer), PHPSTR_LEN(buffer)); - - /* waiting for less data now */ - buffer->hexlen -= PHPSTR_LEN(buffer); - /* no more buffered data */ - phpstr_reset(PHPSTR(buffer)); - /* break */ - } - - /* we have too less data and don't need to flush */ - else { - break; - } - } - - /* we seem to have all data of the chunk */ - else { - out_avail = 1; - NEW_BUCKET(PHPSTR_VAL(buffer), buffer->hexlen); - - /* remove outgoing data from the buffer */ - phpstr_cut(PHPSTR(buffer), 0, buffer->hexlen); - /* reset hexlen */ - buffer->hexlen = 0; - /* continue */ - } - } - - /* we don't know the length of the chunk yet */ - else { - size_t off = 0; - - /* ignore preceeding CRLFs (too loose?) */ - while (off < PHPSTR_LEN(buffer) && ( - PHPSTR_VAL(buffer)[off] == '\n' || - PHPSTR_VAL(buffer)[off] == '\r')) { - ++off; - } - if (off) { - phpstr_cut(PHPSTR(buffer), 0, off); - } - - /* still data there? */ - if (PHPSTR_LEN(buffer)) { - int eollen; - const char *eolstr; - - /* we need eol, so we can be sure we have all hex digits */ - phpstr_fix(PHPSTR(buffer)); - if ((eolstr = http_locate_eol(PHPSTR_VAL(buffer), &eollen))) { - char *stop = NULL; - - /* read in chunk size */ - buffer->hexlen = strtoul(PHPSTR_VAL(buffer), &stop, 16); - - /* if strtoul() stops at the beginning of the buffered data - there's domething oddly wrong, i.e. bad input */ - if (stop == PHPSTR_VAL(buffer)) { - return PSFS_ERR_FATAL; - } - - /* cut out */ - phpstr_cut(PHPSTR(buffer), 0, eolstr + eollen - PHPSTR_VAL(buffer)); - /* buffer->hexlen is 0 now or contains the size of the next chunk */ - /* continue */ - } else { - /* we have not enough data buffered to read in chunk size */ - break; - } - } - /* break */ - } - } - - /* flush before close, but only if we are already waiting for more data */ - if ((flags & PSFS_FLAG_FLUSH_CLOSE) && buffer->hexlen && PHPSTR_LEN(buffer)) { - out_avail = 1; - NEW_BUCKET(PHPSTR_VAL(buffer), PHPSTR_LEN(buffer)); - phpstr_reset(PHPSTR(buffer)); - buffer->hexlen = 0; - } - - return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME; -} - -static HTTP_FILTER_DESTRUCTOR(chunked_decode) -{ - HTTP_FILTER_BUFFER(chunked_decode) *b = (HTTP_FILTER_BUFFER(chunked_decode) *) (this->abstract); - - phpstr_dtor(PHPSTR(b)); - pefree(b, this->is_persistent); -} - -static HTTP_FILTER_FUNCTION(chunked_encode) -{ - int out_avail = 0; - php_stream_bucket *ptr, *nxt; - - if (bytes_consumed) { - *bytes_consumed = 0; - } - - /* new data available? */ - if (buckets_in->head) { - phpstr buf; - out_avail = 1; - - phpstr_init(&buf); - - /* fetch available bucket data */ - for (ptr = buckets_in->head; ptr; ptr = nxt) { - nxt = ptr->next; - if (bytes_consumed) { - *bytes_consumed += ptr->buflen; - } - - phpstr_appendf(&buf, "%x" HTTP_CRLF, ptr->buflen); - phpstr_append(&buf, ptr->buf, ptr->buflen); - phpstr_appends(&buf, HTTP_CRLF); - - /* pass through */ - NEW_BUCKET(PHPSTR_VAL(&buf), PHPSTR_LEN(&buf)); - /* reset */ - phpstr_reset(&buf); - - php_stream_bucket_unlink(ptr TSRMLS_CC); - php_stream_bucket_delref(ptr TSRMLS_CC); - } - - /* free buffer */ - phpstr_dtor(&buf); - } - - /* terminate with "0" */ - if (flags & PSFS_FLAG_FLUSH_CLOSE) { - out_avail = 1; - NEW_BUCKET("0" HTTP_CRLF, lenof("0" HTTP_CRLF)); - } - - return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME; -} - -static HTTP_FILTER_OPS(chunked_decode) = { - HTTP_FILTER_FUNC(chunked_decode), - HTTP_FILTER_DTOR(chunked_decode), - "http.chunked_decode" -}; - -static HTTP_FILTER_OPS(chunked_encode) = { - HTTP_FILTER_FUNC(chunked_encode), - NULL, - "http.chunked_encode" -}; - -#ifdef HTTP_HAVE_ZLIB - -static HTTP_FILTER_FUNCTION(deflate) -{ - int out_avail = 0; - php_stream_bucket *ptr, *nxt; - HTTP_FILTER_BUFFER(inflate) *buffer = (HTTP_FILTER_BUFFER(deflate) *) this->abstract; - - if (bytes_consumed) { - *bytes_consumed = 0; - } - - /* new data available? */ - if (buckets_in->head) { - - /* fetch available bucket data */ - for (ptr = buckets_in->head; ptr; ptr = nxt) { - char *encoded = NULL; - size_t encoded_len = 0; - - nxt = ptr->next; - if (bytes_consumed) { - *bytes_consumed += ptr->buflen; - } - - if (ptr->buflen) { - http_encoding_deflate_stream_update(buffer, ptr->buf, ptr->buflen, &encoded, &encoded_len); - if (encoded) { - if (encoded_len) { - out_avail = 1; - NEW_BUCKET(encoded, encoded_len); - } - efree(encoded); - } - } - - php_stream_bucket_unlink(ptr TSRMLS_CC); - php_stream_bucket_delref(ptr TSRMLS_CC); - } - } - - /* flush & close */ - if (flags & PSFS_FLAG_FLUSH_INC) { - char *encoded = NULL; - size_t encoded_len = 0; - - http_encoding_deflate_stream_flush(buffer, &encoded, &encoded_len); - if (encoded) { - if (encoded_len) { - out_avail = 1; - NEW_BUCKET(encoded, encoded_len); - } - efree(encoded); - } - } - - if (flags & PSFS_FLAG_FLUSH_CLOSE) { - char *encoded = NULL; - size_t encoded_len = 0; - - http_encoding_deflate_stream_finish(buffer, &encoded, &encoded_len); - if (encoded) { - if (encoded_len) { - out_avail = 1; - NEW_BUCKET(encoded, encoded_len); - } - efree(encoded); - } - } - - return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME; -} - -static HTTP_FILTER_FUNCTION(inflate) -{ - int out_avail = 0; - php_stream_bucket *ptr, *nxt; - HTTP_FILTER_BUFFER(inflate) *buffer = (HTTP_FILTER_BUFFER(inflate) *) this->abstract; - - if (bytes_consumed) { - *bytes_consumed = 0; - } - - /* new data available? */ - if (buckets_in->head) { - - /* fetch available bucket data */ - for (ptr = buckets_in->head; ptr; ptr = nxt) { - char *decoded = NULL; - size_t decoded_len = 0; - - nxt = ptr->next; - if (bytes_consumed) { - *bytes_consumed += ptr->buflen; - } - - if (ptr->buflen) { - http_encoding_inflate_stream_update(buffer, ptr->buf, ptr->buflen, &decoded, &decoded_len); - if (decoded) { - if (decoded_len) { - out_avail = 1; - NEW_BUCKET(decoded, decoded_len); - } - efree(decoded); - } - } - - php_stream_bucket_unlink(ptr TSRMLS_CC); - php_stream_bucket_delref(ptr TSRMLS_CC); - } - } - - /* flush & close */ - if (flags & PSFS_FLAG_FLUSH_INC) { - char *decoded = NULL; - size_t decoded_len = 0; - - http_encoding_inflate_stream_flush(buffer, &decoded, &decoded_len); - if (decoded) { - if (decoded_len) { - out_avail = 1; - NEW_BUCKET(decoded, decoded_len); - } - efree(decoded); - } - } - - if (flags & PSFS_FLAG_FLUSH_CLOSE) { - char *decoded = NULL; - size_t decoded_len = 0; - - http_encoding_inflate_stream_finish(buffer, &decoded, &decoded_len); - if (decoded) { - if (decoded_len) { - out_avail = 1; - NEW_BUCKET(decoded, decoded_len); - } - efree(decoded); - } - } - - return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME; -} - -static HTTP_FILTER_DESTRUCTOR(deflate) -{ - HTTP_FILTER_BUFFER(deflate) *buffer = (HTTP_FILTER_BUFFER(deflate) *) this->abstract; - http_encoding_deflate_stream_free(&buffer); -} - -static HTTP_FILTER_DESTRUCTOR(inflate) -{ - HTTP_FILTER_BUFFER(inflate) *buffer = (HTTP_FILTER_BUFFER(inflate) *) this->abstract; - http_encoding_inflate_stream_free(&buffer); -} - -static HTTP_FILTER_OPS(deflate) = { - HTTP_FILTER_FUNC(deflate), - HTTP_FILTER_DTOR(deflate), - "http.deflate" -}; - -static HTTP_FILTER_OPS(inflate) = { - HTTP_FILTER_FUNC(inflate), - HTTP_FILTER_DTOR(inflate), - "http.inflate" -}; - -#endif /* HTTP_HAVE_ZLIB */ - -static php_stream_filter *http_filter_create(const char *name, zval *params, int p TSRMLS_DC) -{ - zval **tmp = ¶ms; - php_stream_filter *f = NULL; - - if (!strcasecmp(name, "http.chunked_decode")) { - HTTP_FILTER_BUFFER(chunked_decode) *b = NULL; - - if ((b = pecalloc(1, sizeof(HTTP_FILTER_BUFFER(chunked_decode)), p))) { - phpstr_init_ex(PHPSTR(b), 4096, p ? PHPSTR_INIT_PERSISTENT : 0); - if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(chunked_decode), b, p))) { - pefree(b, p); - } - } - } else - - if (!strcasecmp(name, "http.chunked_encode")) { - f = php_stream_filter_alloc(&HTTP_FILTER_OP(chunked_encode), NULL, p); -#ifdef HTTP_HAVE_ZLIB - } else - - if (!strcasecmp(name, "http.inflate")) { - int flags = p ? HTTP_ENCODING_STREAM_PERSISTENT : 0; - HTTP_FILTER_BUFFER(inflate) *b = NULL; - - if ((b = http_encoding_inflate_stream_init(NULL, flags))) { - if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(inflate), b, p))) { - http_encoding_inflate_stream_free(&b); - } - } - } else - - if (!strcasecmp(name, "http.deflate")) { - int flags = p ? HTTP_ENCODING_STREAM_PERSISTENT : 0; - HTTP_FILTER_BUFFER(deflate) *b = NULL; - - if (params) { - switch (Z_TYPE_P(params)) { - case IS_ARRAY: - case IS_OBJECT: - if (SUCCESS != zend_hash_find(HASH_OF(params), "flags", sizeof("flags"), (void *) &tmp)) { - break; - } - default: - { - zval *num = http_zsep(IS_LONG, *tmp); - - flags |= (Z_LVAL_P(num) & 0x0fffffff); - zval_ptr_dtor(&num); - } - } - } - if ((b = http_encoding_deflate_stream_init(NULL, flags))) { - if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(deflate), b, p))) { - http_encoding_deflate_stream_free(&b); - } - } -#endif /* HTTP_HAVE_ZLIB */ - } - - return f; -} - -php_stream_filter_factory http_filter_factory = { - http_filter_create -}; - -#endif /* ZEND_ENGINE_2 */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/http_functions.c b/http_functions.c deleted file mode 100644 index 8fc26f2..0000000 --- a/http_functions.c +++ /dev/null @@ -1,1424 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#define HTTP_WANT_CURL -#define HTTP_WANT_ZLIB -#include "php_http.h" - -#include "php_ini.h" -#include "ext/standard/php_string.h" -#include "zend_operators.h" - -#ifdef HTTP_HAVE_SESSION -# include "ext/session/php_session.h" -#endif - -#include "php_http_api.h" -#include "php_http_cache_api.h" -#include "php_http_cookie_api.h" -#include "php_http_date_api.h" -#include "php_http_encoding_api.h" -#include "php_http_headers_api.h" -#include "php_http_message_api.h" -#include "php_http_request_api.h" -#include "php_http_request_method_api.h" -#include "php_http_persistent_handle_api.h" -#include "php_http_send_api.h" -#include "php_http_url_api.h" - -/* {{{ proto string http_date([int timestamp]) - Compose a valid HTTP date regarding RFC 1123 looking like: "Wed, 22 Dec 2004 11:34:47 GMT" */ -PHP_FUNCTION(http_date) -{ - long t = -1; - char *date; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) { - RETURN_FALSE; - } - - if (t == -1) { - t = HTTP_G->request.time; - } - - if (!(date = http_date(t))) { - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Could not compose date of timestamp %ld", t); - RETURN_FALSE; - } - - RETURN_STRING(date, 0); -} -/* }}} */ - -/* {{{ proto string http_build_url([mixed url[, mixed parts[, int flags = HTTP_URL_REPLACE|HTTP_URL_FROM_ENV[, array &new_url]]]]) - Build an URL. */ -PHP_FUNCTION(http_build_url) -{ - char *url_str = NULL; - size_t url_len = 0; - long flags = HTTP_URL_REPLACE|HTTP_URL_FROM_ENV; - zval *z_old_url = NULL, *z_new_url = NULL, *z_composed_url = NULL; - php_url *old_url = NULL, *new_url = NULL, *composed_url = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!/z!/lz", &z_old_url, &z_new_url, &flags, &z_composed_url) != SUCCESS) { - RETURN_FALSE; - } - - if (z_new_url) { - if (Z_TYPE_P(z_new_url) == IS_ARRAY || Z_TYPE_P(z_new_url) == IS_OBJECT) { - new_url = http_url_from_struct(NULL, HASH_OF(z_new_url)); - } else { - convert_to_string(z_new_url); - if (!(new_url = php_url_parse_ex(Z_STRVAL_P(z_new_url), Z_STRLEN_P(z_new_url)))) { - http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", Z_STRVAL_P(z_new_url)); - RETURN_FALSE; - } - } - } - - if (z_old_url) { - if (Z_TYPE_P(z_old_url) == IS_ARRAY || Z_TYPE_P(z_old_url) == IS_OBJECT) { - old_url = http_url_from_struct(NULL, HASH_OF(z_old_url)); - } else { - convert_to_string(z_old_url); - if (!(old_url = php_url_parse_ex(Z_STRVAL_P(z_old_url), Z_STRLEN_P(z_old_url)))) { - if (new_url) { - php_url_free(new_url); - } - http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", Z_STRVAL_P(z_old_url)); - RETURN_FALSE; - } - } - } - - if (z_composed_url) { - http_build_url(flags, old_url, new_url, &composed_url, &url_str, &url_len); - http_url_tostruct(composed_url, z_composed_url); - php_url_free(composed_url); - } else { - http_build_url(flags, old_url, new_url, NULL, &url_str, &url_len); - } - - if (new_url) { - php_url_free(new_url); - } - if (old_url) { - php_url_free(old_url); - } - - RETURN_STRINGL(url_str, url_len, 0); -} -/* }}} */ - -/* {{{ proto string http_build_str(array query [, string prefix[, string arg_separator]]) - Opponent to parse_str(). */ -PHP_FUNCTION(http_build_str) -{ - zval *formdata; - char *prefix = NULL, *arg_sep = INI_STR("arg_separator.output"); - int prefix_len = 0, arg_sep_len = strlen(arg_sep); - phpstr formstr; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|ss", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len) != SUCCESS) { - RETURN_FALSE; - } - - if (!arg_sep_len) { - arg_sep = HTTP_URL_ARGSEP; - arg_sep_len = lenof(HTTP_URL_ARGSEP); - } - - phpstr_init(&formstr); - if (SUCCESS != http_urlencode_hash_recursive(HASH_OF(formdata), &formstr, arg_sep, arg_sep_len, prefix, prefix_len)) { - RETURN_FALSE; - } - - if (!formstr.used) { - phpstr_dtor(&formstr); - RETURN_NULL(); - } - - RETURN_PHPSTR_VAL(&formstr); -} -/* }}} */ - -#define HTTP_DO_NEGOTIATE_DEFAULT(supported) \ - { \ - zval **value; \ - \ - zend_hash_internal_pointer_reset(Z_ARRVAL_P(supported)); \ - if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(supported), (void *) &value)) { \ - RETVAL_ZVAL(*value, 1, 0); \ - } else { \ - RETVAL_NULL(); \ - } \ - } - -#define HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array) \ - HTTP_DO_NEGOTIATE_DEFAULT(supported); \ - if (rs_array) { \ - HashPosition pos; \ - zval **value_ptr; \ - \ - FOREACH_VAL(pos, supported, value_ptr) { \ - zval *value = http_zsep(IS_STRING, *value_ptr); \ - add_assoc_double(rs_array, Z_STRVAL_P(value), 1.0); \ - zval_ptr_dtor(&value); \ - } \ - } - -#define HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array) \ - { \ - char *key; \ - uint key_len; \ - ulong idx; \ - \ - if (zend_hash_num_elements(result) && HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \ - RETVAL_STRINGL(key, key_len-1, 0); \ - } else { \ - HTTP_DO_NEGOTIATE_DEFAULT(supported); \ - } \ - \ - if (rs_array) { \ - zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); \ - } \ - \ - zend_hash_destroy(result); \ - FREE_HASHTABLE(result); \ - } - -#define HTTP_DO_NEGOTIATE(type, supported, rs_array) \ - { \ - HashTable *result; \ - if ((result = http_negotiate_ ##type(supported))) { \ - HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array); \ - } else { \ - HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); \ - } \ - } - -/* {{{ proto string http_negotiate_language(array supported[, array &result]) - Negotiate the clients preferred language. */ -PHP_FUNCTION(http_negotiate_language) -{ - zval *supported, *rs_array = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array) != SUCCESS) { - RETURN_FALSE; - } - - if (rs_array) { - zval_dtor(rs_array); - array_init(rs_array); - } - - HTTP_DO_NEGOTIATE(language, supported, rs_array); -} -/* }}} */ - -/* {{{ proto string http_negotiate_charset(array supported[, array &result]) - Negotiate the clients preferred charset. */ -PHP_FUNCTION(http_negotiate_charset) -{ - zval *supported, *rs_array = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array) != SUCCESS) { - RETURN_FALSE; - } - - if (rs_array) { - zval_dtor(rs_array); - array_init(rs_array); - } - - HTTP_DO_NEGOTIATE(charset, supported, rs_array); -} -/* }}} */ - -/* {{{ proto string http_negotiate_content_type(array supported[, array &result]) - Negotiate the clients preferred content type. */ -PHP_FUNCTION(http_negotiate_content_type) -{ - zval *supported, *rs_array = NULL; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &supported, &rs_array)) { - RETURN_FALSE; - } - - if (rs_array) { - zval_dtor(rs_array); - array_init(rs_array); - } - - HTTP_DO_NEGOTIATE(content_type, supported, rs_array); -} -/* }}} */ - -/* {{{ proto string http_negotiate(mixed value, array supported[, array &result]) - Negotiate the user supplied value. */ -PHP_FUNCTION(http_negotiate) -{ - zval *value, *supported, *rs_array = NULL; - HashTable *rs; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za|z", &value, &supported, &rs_array)) { - RETURN_FALSE; - } - - if (rs_array) { - zval_dtor(rs_array); - array_init(rs_array); - } - - if ((rs = http_negotiate_z(value, Z_ARRVAL_P(supported), http_negotiate_default_func))) { - HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array); - } else { - HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); - } -} -/* }}} */ - -/* {{{ proto bool http_send_status(int status) - Send HTTP status code. */ -PHP_FUNCTION(http_send_status) -{ - long status = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status) != SUCCESS) { - RETURN_FALSE; - } - if (status < 100 || status > 510) { - http_error_ex(HE_WARNING, HTTP_E_HEADER, "Invalid HTTP status code (100-510): %d", status); - RETURN_FALSE; - } - - RETURN_SUCCESS(http_send_status(status)); -} -/* }}} */ - -/* {{{ proto bool http_send_last_modified([int timestamp]) - Send a "Last-Modified" header with a valid HTTP date. */ -PHP_FUNCTION(http_send_last_modified) -{ - long t = -1; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) { - RETURN_FALSE; - } - - if (t == -1) { - t = HTTP_G->request.time; - } - - RETURN_SUCCESS(http_send_last_modified(t)); -} -/* }}} */ - -/* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream']) - Send the Content-Type of the sent entity. This is particularly important if you use the http_send() API. */ -PHP_FUNCTION(http_send_content_type) -{ - char *ct = "application/x-octetstream"; - int ct_len = lenof("application/x-octetstream"); - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ct, &ct_len) != SUCCESS) { - RETURN_FALSE; - } - - RETURN_SUCCESS(http_send_content_type(ct, ct_len)); -} -/* }}} */ - -/* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false]) - Send the Content-Disposition. */ -PHP_FUNCTION(http_send_content_disposition) -{ - char *filename; - int f_len; - zend_bool send_inline = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &filename, &f_len, &send_inline) != SUCCESS) { - RETURN_FALSE; - } - RETURN_SUCCESS(http_send_content_disposition(filename, f_len, send_inline)); -} -/* }}} */ - -/* {{{ proto bool http_match_modified([int timestamp[, bool for_range = false]]) - Matches the given unix timestamp against the clients "If-Modified-Since" resp. "If-Unmodified-Since" HTTP headers. */ -PHP_FUNCTION(http_match_modified) -{ - long t = -1; - zend_bool for_range = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &t, &for_range) != SUCCESS) { - RETURN_FALSE; - } - - // current time if not supplied (senseless though) - if (t == -1) { - t = HTTP_G->request.time; - } - - if (for_range) { - RETURN_BOOL(http_match_last_modified("HTTP_IF_UNMODIFIED_SINCE", t)); - } - RETURN_BOOL(http_match_last_modified("HTTP_IF_MODIFIED_SINCE", t)); -} -/* }}} */ - -/* {{{ proto bool http_match_etag(string etag[, bool for_range = false]) - Matches the given ETag against the clients "If-Match" resp. "If-None-Match" HTTP headers. */ -PHP_FUNCTION(http_match_etag) -{ - int etag_len; - char *etag; - zend_bool for_range = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &etag, &etag_len, &for_range) != SUCCESS) { - RETURN_FALSE; - } - - if (for_range) { - RETURN_BOOL(http_match_etag("HTTP_IF_MATCH", etag)); - } - RETURN_BOOL(http_match_etag("HTTP_IF_NONE_MATCH", etag)); -} -/* }}} */ - -/* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]]) - Attempts to cache the sent entity by its last modification date. */ -PHP_FUNCTION(http_cache_last_modified) -{ - long last_modified = 0, send_modified = 0, t; - zval *zlm; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) { - RETURN_FALSE; - } - - HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); - - t = HTTP_G->request.time; - - /* 0 or omitted */ - if (!last_modified) { - /* does the client have? (att: caching "forever") */ - if ((zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE", 1))) { - last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm)); - /* send current time */ - } else { - send_modified = t; - } - /* negative value is supposed to be expiration time */ - } else if (last_modified < 0) { - last_modified += t; - send_modified = t; - /* send supplied time explicitly */ - } else { - send_modified = last_modified; - } - - RETURN_SUCCESS(http_cache_last_modified(last_modified, send_modified, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL))); -} -/* }}} */ - -/* {{{ proto bool http_cache_etag([string etag]) - Attempts to cache the sent entity by its ETag, either supplied or generated by the hash algorithm specified by the INI setting "http.etag.mode". */ -PHP_FUNCTION(http_cache_etag) -{ - char *etag = NULL; - int etag_len = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) { - RETURN_FALSE; - } - - HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); - - RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL))); -} -/* }}} */ - -/* {{{ proto string ob_etaghandler(string data, int mode) - For use with ob_start(). Output buffer handler generating an ETag with the hash algorithm specified with the INI setting "http.etag.mode". */ -PHP_FUNCTION(ob_etaghandler) -{ - char *data; - int data_len; - long mode; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) { - RETURN_FALSE; - } - - Z_TYPE_P(return_value) = IS_STRING; - http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode); -} -/* }}} */ - -/* {{{ proto void http_throttle(double sec[, int bytes = 40960]) - Sets the throttle delay and send buffer size for use with http_send() API. */ -PHP_FUNCTION(http_throttle) -{ - long chunk_size = HTTP_SENDBUF_SIZE; - double interval; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|l", &interval, &chunk_size)) { - return; - } - - HTTP_G->send.throttle_delay = interval; - HTTP_G->send.buffer_size = chunk_size; -} -/* }}} */ - -/* {{{ proto void http_redirect([string url[, array params[, bool session = false[, int status = 302]]]]) - Redirect to the given url. */ -PHP_FUNCTION(http_redirect) -{ - int url_len = 0; - size_t query_len = 0; - zend_bool session = 0, free_params = 0; - zval *params = NULL; - long status = HTTP_REDIRECT; - char *query = NULL, *url = NULL, *URI, *LOC, *RED = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bl", &url, &url_len, ¶ms, &session, &status) != SUCCESS) { - RETURN_FALSE; - } - -#ifdef HTTP_HAVE_SESSION - /* append session info */ - if (session) { - if (!params) { - free_params = 1; - MAKE_STD_ZVAL(params); - array_init(params); - } - if (PS(session_status) == php_session_active) { - if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) { - http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not append session information"); - } - } - } -#endif - - /* treat params array with http_build_query() */ - if (params) { - if (SUCCESS != http_urlencode_hash_ex(Z_ARRVAL_P(params), 0, NULL, 0, &query, &query_len)) { - if (free_params) { - zval_dtor(params); - FREE_ZVAL(params); - } - if (query) { - efree(query); - } - RETURN_FALSE; - } - } - - URI = http_absolute_url_ex(url, HTTP_URL_FROM_ENV); - - if (query_len) { - spprintf(&LOC, 0, "Location: %s?%s", URI, query); - if (status != 300) { - spprintf(&RED, 0, "Redirecting to %s?%s.\n", URI, query, URI, query); - } - } else { - spprintf(&LOC, 0, "Location: %s", URI); - if (status != 300) { - spprintf(&RED, 0, "Redirecting to %s.\n", URI, URI); - } - } - - efree(URI); - if (query) { - efree(query); - } - if (free_params) { - zval_dtor(params); - FREE_ZVAL(params); - } - - switch (status) { - case 300: - RETVAL_SUCCESS(http_send_status_header(status, LOC)); - efree(LOC); - return; - - case HTTP_REDIRECT_PERM: - case HTTP_REDIRECT_FOUND: - case HTTP_REDIRECT_POST: - case HTTP_REDIRECT_PROXY: - case HTTP_REDIRECT_TEMP: - break; - - case 306: - default: - http_error_ex(HE_NOTICE, HTTP_E_RUNTIME, "Unsupported redirection status code: %ld", status); - case HTTP_REDIRECT: - if ( SG(request_info).request_method && - strcasecmp(SG(request_info).request_method, "HEAD") && - strcasecmp(SG(request_info).request_method, "GET")) { - status = HTTP_REDIRECT_POST; - } else { - status = HTTP_REDIRECT_FOUND; - } - break; - } - - RETURN_SUCCESS(http_exit_ex(status, LOC, RED, 1)); -} -/* }}} */ - -/* {{{ proto bool http_send_data(string data) - Sends raw data with support for (multiple) range requests. */ -PHP_FUNCTION(http_send_data) -{ - int data_len; - char *data_buf; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_buf, &data_len) != SUCCESS) { - RETURN_FALSE; - } - - RETURN_SUCCESS(http_send_data(data_buf, data_len)); -} -/* }}} */ - -/* {{{ proto bool http_send_file(string file) - Sends a file with support for (multiple) range requests. */ -PHP_FUNCTION(http_send_file) -{ - char *file; - int flen = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &flen) != SUCCESS) { - RETURN_FALSE; - } - if (!flen) { - RETURN_FALSE; - } - - RETURN_SUCCESS(http_send_file(file)); -} -/* }}} */ - -/* {{{ proto bool http_send_stream(resource stream) - Sends an already opened stream with support for (multiple) range requests. */ -PHP_FUNCTION(http_send_stream) -{ - zval *zstream; - php_stream *file; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) != SUCCESS) { - RETURN_FALSE; - } - - php_stream_from_zval(file, &zstream); - RETURN_SUCCESS(http_send_stream(file)); -} -/* }}} */ - -/* {{{ proto string http_chunked_decode(string encoded) - Decodes a string that was HTTP-chunked encoded. */ -PHP_FUNCTION(http_chunked_decode) -{ - char *encoded = NULL, *decoded = NULL; - size_t decoded_len = 0; - int encoded_len = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) { - RETURN_FALSE; - } - - if (NULL != http_encoding_dechunk(encoded, encoded_len, &decoded, &decoded_len)) { - RETURN_STRINGL(decoded, (int) decoded_len, 0); - } else { - RETURN_FALSE; - } -} -/* }}} */ - -/* {{{ proto object http_parse_message(string message) - Parses (a) http_message(s) into a simple recursive object structure. */ -PHP_FUNCTION(http_parse_message) -{ - char *message; - int message_len; - http_message *msg = NULL; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &message, &message_len)) { - RETURN_NULL(); - } - - if ((msg = http_message_parse(message, message_len))) { - object_init(return_value); - http_message_tostruct_recursive(msg, return_value); - http_message_free(&msg); - } else { - RETURN_NULL(); - } -} -/* }}} */ - -/* {{{ proto array http_parse_headers(string header) - Parses HTTP headers into an associative array. */ -PHP_FUNCTION(http_parse_headers) -{ - char *header; - int header_len; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) { - RETURN_FALSE; - } - - array_init(return_value); - if (SUCCESS != http_parse_headers(header, return_value)) { - zval_dtor(return_value); - http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Failed to parse headers"); - RETURN_FALSE; - } -} -/* }}}*/ - -/* {{{ proto object http_parse_cookie(string cookie[, int flags[, array allowed_extras]]) - Parses HTTP cookies like sent in a response into a struct. */ -PHP_FUNCTION(http_parse_cookie) -{ - char *cookie, **allowed_extras = NULL; - int i = 0, cookie_len; - long flags = 0; - zval *allowed_extras_array = NULL, **entry = NULL; - HashPosition pos; - http_cookie_list list; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la!", &cookie, &cookie_len, &flags, &allowed_extras_array)) { - RETURN_FALSE; - } - - if (allowed_extras_array) { - allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *)); - FOREACH_VAL(pos, allowed_extras_array, entry) { - zval *data = http_zsep(IS_STRING, *entry); - allowed_extras[i++] = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data)); - zval_ptr_dtor(&data); - } - } - - if (http_parse_cookie_ex(&list, cookie, flags, allowed_extras)) { - object_init(return_value); - http_cookie_list_tostruct(&list, return_value); - http_cookie_list_dtor(&list); - } else { - RETVAL_FALSE; - } - - if (allowed_extras) { - for (i = 0; allowed_extras[i]; ++i) { - efree(allowed_extras[i]); - } - efree(allowed_extras); - } -} -/* }}} */ - -/* {{{ proto string http_build_cookie(array cookie) - Build a cookie string from an array/object like returned by http_parse_cookie(). */ -PHP_FUNCTION(http_build_cookie) -{ - char *str = NULL; - size_t len = 0; - zval *strct; - http_cookie_list list; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &strct)) { - RETURN_FALSE; - } - - http_cookie_list_fromstruct(&list, strct); - http_cookie_list_tostring(&list, &str, &len); - http_cookie_list_dtor(&list); - - RETURN_STRINGL(str, len, 0); -} -/* }}} */ - -/* {{{ proto object http_parse_params(string param[, int flags = HTTP_PARAMS_DEFAULT]) - Parse parameter list. */ -PHP_FUNCTION(http_parse_params) -{ - char *param; - int param_len; - zval *params; - long flags = HTTP_PARAMS_DEFAULT; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", ¶m, ¶m_len, &flags)) { - RETURN_FALSE; - } - - MAKE_STD_ZVAL(params); - array_init(params); - if (SUCCESS != http_parse_params(param, flags, Z_ARRVAL_P(params))) { - zval_ptr_dtor(¶ms); - RETURN_FALSE; - } - - object_init(return_value); - add_property_zval(return_value, "params", params); -#ifdef ZEND_ENGINE_2 - zval_ptr_dtor(¶ms); -#endif -} -/* }}} */ - -/* {{{ proto array http_get_request_headers(void) - Get a list of incoming HTTP headers. */ -PHP_FUNCTION(http_get_request_headers) -{ - NO_ARGS; - - array_init(return_value); - http_get_request_headers(Z_ARRVAL_P(return_value)); -} -/* }}} */ - -/* {{{ proto string http_get_request_body(void) - Get the raw request body (e.g. POST or PUT data). */ -PHP_FUNCTION(http_get_request_body) -{ - char *body; - size_t length; - - NO_ARGS; - - if (SUCCESS == http_get_request_body(&body, &length)) { - RETURN_STRINGL(body, (int) length, 0); - } else { - RETURN_NULL(); - } -} -/* }}} */ - -/* {{{ proto resource http_get_request_body_stream(void) - Create a stream to read the raw request body (e.g. POST or PUT data). This function can only be used once if the request method was another than POST. */ -PHP_FUNCTION(http_get_request_body_stream) -{ - php_stream *s; - - NO_ARGS; - - if ((s = http_get_request_body_stream())) { - php_stream_to_zval(s, return_value); - } else { - http_error(HE_WARNING, HTTP_E_RUNTIME, "Failed to create request body stream"); - RETURN_NULL(); - } -} -/* }}} */ - -/* {{{ proto bool http_match_request_header(string header, string value[, bool match_case = false]) - Match an incoming HTTP header. */ -PHP_FUNCTION(http_match_request_header) -{ - char *header, *value; - int header_len, value_len; - zend_bool match_case = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &header, &header_len, &value, &value_len, &match_case)) { - RETURN_FALSE; - } - - RETURN_BOOL(http_match_request_header_ex(header, value, match_case)); -} -/* }}} */ - -/* {{{ proto object http_persistent_handles_count() */ -PHP_FUNCTION(http_persistent_handles_count) -{ - NO_ARGS; - object_init(return_value); - if (!http_persistent_handle_statall_ex(HASH_OF(return_value))) { - zval_dtor(return_value); - RETURN_NULL(); - } -} -/* }}} */ - -/* {{{ proto void http_persistent_handles_clean([string name]) */ -PHP_FUNCTION(http_persistent_handles_clean) -{ - char *name_str = NULL; - int name_len = 0; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name_str, &name_len)) { - http_persistent_handle_cleanup_ex(name_str, name_len, 1); - } -} -/* }}} */ - -/* {{{ proto string http_persistent_handles_ident([string ident]) */ -PHP_FUNCTION(http_persistent_handles_ident) -{ - char *ident_str = NULL; - int ident_len = 0; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ident_str, &ident_len)) { - RETVAL_STRING(zend_ini_string(ZEND_STRS("http.persistent.handles.ident"), 0), 1); - if (ident_str && ident_len) { - zend_alter_ini_entry(ZEND_STRS("http.persistent.handles.ident"), ident_str, ident_len, ZEND_INI_USER, PHP_INI_STAGE_RUNTIME); - } - } -} -/* }}} */ - -/* {{{ HAVE_CURL */ -#ifdef HTTP_HAVE_CURL - -#define RETVAL_RESPONSE_OR_BODY(request) \ - { \ - zval **bodyonly; \ - \ - /* check if only the body should be returned */ \ - if (options && (SUCCESS == zend_hash_find(Z_ARRVAL_P(options), "bodyonly", sizeof("bodyonly"), (void *) &bodyonly)) && i_zend_is_true(*bodyonly)) { \ - http_message *msg = http_message_parse(PHPSTR_VAL(&request.conv.response), PHPSTR_LEN(&request.conv.response)); \ - \ - if (msg) { \ - RETVAL_STRINGL(PHPSTR_VAL(&msg->body), PHPSTR_LEN(&msg->body), 1); \ - http_message_free(&msg); \ - } \ - } else { \ - RETVAL_STRINGL(request.conv.response.data, request.conv.response.used, 1); \ - } \ - } - -/* {{{ proto string http_get(string url[, array options[, array &info]]) - Performs an HTTP GET request on the supplied url. */ -PHP_FUNCTION(http_get) -{ - zval *options = NULL, *info = NULL; - char *URL; - int URL_len; - http_request request; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) { - RETURN_FALSE; - } - - if (info) { - zval_dtor(info); - array_init(info); - } - - RETVAL_FALSE; - - http_request_init_ex(&request, NULL, HTTP_GET, URL); - if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { - http_request_exec(&request); - if (info) { - http_request_info(&request, Z_ARRVAL_P(info)); - } - RETVAL_RESPONSE_OR_BODY(request); - } - http_request_dtor(&request); -} -/* }}} */ - -/* {{{ proto string http_head(string url[, array options[, array &info]]) - Performs an HTTP HEAD request on the supplied url. */ -PHP_FUNCTION(http_head) -{ - zval *options = NULL, *info = NULL; - char *URL; - int URL_len; - http_request request; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) { - RETURN_FALSE; - } - - if (info) { - zval_dtor(info); - array_init(info); - } - - RETVAL_FALSE; - - http_request_init_ex(&request, NULL, HTTP_HEAD, URL); - if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { - http_request_exec(&request); - if (info) { - http_request_info(&request, Z_ARRVAL_P(info)); - } - RETVAL_RESPONSE_OR_BODY(request); - } - http_request_dtor(&request); -} -/* }}} */ - -/* {{{ proto string http_post_data(string url, string data[, array options[, array &info]]) - Performs an HTTP POST request on the supplied url. */ -PHP_FUNCTION(http_post_data) -{ - zval *options = NULL, *info = NULL; - char *URL, *postdata; - int postdata_len, URL_len; - http_request_body body; - http_request request; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) { - RETURN_FALSE; - } - - if (info) { - zval_dtor(info); - array_init(info); - } - - RETVAL_FALSE; - - http_request_init_ex(&request, NULL, HTTP_POST, URL); - request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, postdata, postdata_len, 0); - if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { - http_request_exec(&request); - if (info) { - http_request_info(&request, Z_ARRVAL_P(info)); - } - RETVAL_RESPONSE_OR_BODY(request); - } - http_request_dtor(&request); -} -/* }}} */ - -/* {{{ proto string http_post_fields(string url, array data[, array files[, array options[, array &info]]]) - Performs an HTTP POST request on the supplied url. */ -PHP_FUNCTION(http_post_fields) -{ - zval *options = NULL, *info = NULL, *fields = NULL, *files = NULL; - char *URL; - int URL_len; - http_request_body body; - http_request request; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa!|a!a/!z", &URL, &URL_len, &fields, &files, &options, &info) != SUCCESS) { - RETURN_FALSE; - } - - if (!http_request_body_fill(&body, fields ? Z_ARRVAL_P(fields) : NULL, files ? Z_ARRVAL_P(files) : NULL)) { - RETURN_FALSE; - } - - if (info) { - zval_dtor(info); - array_init(info); - } - - RETVAL_FALSE; - - http_request_init_ex(&request, NULL, HTTP_POST, URL); - request.body = &body; - if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { - http_request_exec(&request); - if (info) { - http_request_info(&request, Z_ARRVAL_P(info)); - } - RETVAL_RESPONSE_OR_BODY(request); - } - http_request_dtor(&request); -} -/* }}} */ - -/* {{{ proto string http_put_file(string url, string file[, array options[, array &info]]) - Performs an HTTP PUT request on the supplied url. */ -PHP_FUNCTION(http_put_file) -{ - char *URL, *file; - int URL_len, f_len; - zval *options = NULL, *info = NULL; - php_stream *stream; - php_stream_statbuf ssb; - http_request_body body; - http_request request; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &file, &f_len, &options, &info)) { - RETURN_FALSE; - } - - if (!(stream = php_stream_open_wrapper_ex(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT))) { - RETURN_FALSE; - } - if (php_stream_stat(stream, &ssb)) { - php_stream_close(stream); - RETURN_FALSE; - } - - if (info) { - zval_dtor(info); - array_init(info); - } - - RETVAL_FALSE; - - http_request_init_ex(&request, NULL, HTTP_PUT, URL); - request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 1); - if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { - http_request_exec(&request); - if (info) { - http_request_info(&request, Z_ARRVAL_P(info)); - } - RETVAL_RESPONSE_OR_BODY(request); - } - http_request_dtor(&request); -} -/* }}} */ - -/* {{{ proto string http_put_stream(string url, resource stream[, array options[, array &info]]) - Performs an HTTP PUT request on the supplied url. */ -PHP_FUNCTION(http_put_stream) -{ - zval *resource, *options = NULL, *info = NULL; - char *URL; - int URL_len; - php_stream *stream; - php_stream_statbuf ssb; - http_request_body body; - http_request request; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr|a/!z", &URL, &URL_len, &resource, &options, &info)) { - RETURN_FALSE; - } - - php_stream_from_zval(stream, &resource); - if (php_stream_stat(stream, &ssb)) { - RETURN_FALSE; - } - - if (info) { - zval_dtor(info); - array_init(info); - } - - RETVAL_FALSE; - - http_request_init_ex(&request, NULL, HTTP_PUT, URL); - request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 0); - if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { - http_request_exec(&request); - if (info) { - http_request_info(&request, Z_ARRVAL_P(info)); - } - RETVAL_RESPONSE_OR_BODY(request); - } - http_request_dtor(&request); -} -/* }}} */ - -/* {{{ proto string http_put_data(string url, string data[, array options[, array &info]]) - Performs an HTTP PUT request on the supplied url. */ -PHP_FUNCTION(http_put_data) -{ - char *URL, *data; - int URL_len, data_len; - zval *options = NULL, *info = NULL; - http_request_body body; - http_request request; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &data, &data_len, &options, &info)) { - RETURN_FALSE; - } - - if (info) { - zval_dtor(info); - array_init(info); - } - - RETVAL_FALSE; - - http_request_init_ex(&request, NULL, HTTP_PUT, URL); - request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, data, data_len, 0); - if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { - http_request_exec(&request); - if (info) { - http_request_info(&request, Z_ARRVAL_P(info)); - } - RETVAL_RESPONSE_OR_BODY(request); - } - http_request_dtor(&request); -} -/* }}} */ - -/* {{{ proto string http_request(int method, string url[, string body[, array options[, array &info]]]) - Performs a custom HTTP request on the supplied url. */ -PHP_FUNCTION(http_request) -{ - long meth; - char *URL, *data = NULL; - int URL_len, data_len = 0; - zval *options = NULL, *info = NULL; - http_request_body body; - http_request request; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls|sa/!z", &meth, &URL, &URL_len, &data, &data_len, &options, &info)) { - RETURN_FALSE; - } - - if (info) { - zval_dtor(info); - array_init(info); - } - - RETVAL_FALSE; - - http_request_init_ex(&request, NULL, meth, URL); - request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, data, data_len, 0); - if (SUCCESS == http_request_prepare(&request, options?Z_ARRVAL_P(options):NULL)) { - http_request_exec(&request); - if (info) { - http_request_info(&request, Z_ARRVAL_P(info)); - } - RETVAL_RESPONSE_OR_BODY(request); - } - http_request_dtor(&request); -} -/* }}} */ - -/* {{{ proto string http_request_body_encode(array fields, array files) - Generate x-www-form-urlencoded resp. form-data encoded request body. */ -PHP_FUNCTION(http_request_body_encode) -{ - zval *fields = NULL, *files = NULL; - HashTable *fields_ht, *files_ht; - http_request_body body; - char *buf; - size_t len; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!", &fields, &files)) { - RETURN_FALSE; - } - - fields_ht = (fields && Z_TYPE_P(fields) == IS_ARRAY) ? Z_ARRVAL_P(fields) : NULL; - files_ht = (files && Z_TYPE_P(files) == IS_ARRAY) ? Z_ARRVAL_P(files) : NULL; - if (http_request_body_fill(&body, fields_ht, files_ht) && (SUCCESS == http_request_body_encode(&body, &buf, &len))) { - RETVAL_STRINGL(buf, len, 0); - } else { - http_error(HE_WARNING, HTTP_E_RUNTIME, "Could not encode request body"); - RETVAL_FALSE; - } - http_request_body_dtor(&body); -} -#endif /* HTTP_HAVE_CURL */ -/* }}} HAVE_CURL */ - -/* {{{ proto int http_request_method_register(string method) - Register a custom request method. */ -PHP_FUNCTION(http_request_method_register) -{ - char *method; - int method_len; - ulong existing; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) { - RETURN_FALSE; - } - if ((existing = http_request_method_exists(1, 0, method))) { - RETURN_LONG((long) existing); - } - - RETVAL_LONG((long) http_request_method_register(method, method_len)); -} -/* }}} */ - -/* {{{ proto bool http_request_method_unregister(mixed method) - Unregister a previously registered custom request method. */ -PHP_FUNCTION(http_request_method_unregister) -{ - zval *method; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) { - RETURN_FALSE; - } - - switch (Z_TYPE_P(method)) { - case IS_OBJECT: - convert_to_string(method); - case IS_STRING: - if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) { - convert_to_long(method); - } else { - int mn; - if (!(mn = http_request_method_exists(1, 0, Z_STRVAL_P(method)))) { - RETURN_FALSE; - } - zval_dtor(method); - ZVAL_LONG(method, (long)mn); - } - case IS_LONG: - RETURN_SUCCESS(http_request_method_unregister(Z_LVAL_P(method))); - default: - RETURN_FALSE; - } -} -/* }}} */ - -/* {{{ proto int http_request_method_exists(mixed method) - Check if a request method is registered (or available by default). */ -PHP_FUNCTION(http_request_method_exists) -{ - if (return_value_used) { - zval *method; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &method)) { - RETURN_FALSE; - } - - switch (Z_TYPE_P(method)) { - case IS_OBJECT: - convert_to_string(method); - case IS_STRING: - if (is_numeric_string(Z_STRVAL_P(method), Z_STRLEN_P(method), NULL, NULL, 1)) { - convert_to_long(method); - } else { - RETURN_LONG((long) http_request_method_exists(1, 0, Z_STRVAL_P(method))); - } - case IS_LONG: - RETURN_LONG((long) http_request_method_exists(0, (int) Z_LVAL_P(method), NULL)); - default: - RETURN_FALSE; - } - } -} -/* }}} */ - -/* {{{ proto string http_request_method_name(int method) - Get the literal string representation of a standard or registered request method. */ -PHP_FUNCTION(http_request_method_name) -{ - if (return_value_used) { - long method; - - if ((SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method)) || (method < 0)) { - RETURN_FALSE; - } - - RETURN_STRING(estrdup(http_request_method_name((int) method)), 0); - } -} -/* }}} */ - -/* {{{ */ -#ifdef HTTP_HAVE_ZLIB - -/* {{{ proto string http_deflate(string data[, int flags = 0]) - Compress data with gzip, zlib AKA deflate or raw deflate encoding. */ -PHP_FUNCTION(http_deflate) -{ - char *data; - int data_len; - long flags = 0; - - RETVAL_NULL(); - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &flags)) { - char *encoded; - size_t encoded_len; - - if (SUCCESS == http_encoding_deflate(flags, data, data_len, &encoded, &encoded_len)) { - RETURN_STRINGL(encoded, (int) encoded_len, 0); - } - } -} -/* }}} */ - -/* {{{ proto string http_inflate(string data) - Decompress data compressed with either gzip, deflate AKA zlib or raw deflate encoding. */ -PHP_FUNCTION(http_inflate) -{ - char *data; - int data_len; - - RETVAL_NULL(); - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) { - char *decoded; - size_t decoded_len; - - if (SUCCESS == http_encoding_inflate(data, data_len, &decoded, &decoded_len)) { - RETURN_STRINGL(decoded, (int) decoded_len, 0); - } - } -} -/* }}} */ - -/* {{{ proto string ob_deflatehandler(string data, int mode) - For use with ob_start(). The deflate output buffer handler can only be used once. */ -PHP_FUNCTION(ob_deflatehandler) -{ - char *data; - int data_len; - long mode; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) { - RETURN_FALSE; - } - - http_ob_deflatehandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode); - Z_TYPE_P(return_value) = Z_STRVAL_P(return_value) ? IS_STRING : IS_NULL; -} -/* }}} */ - -/* {{{ proto string ob_inflatehandler(string data, int mode) - For use with ob_start(). Same restrictions as with ob_deflatehandler apply. */ -PHP_FUNCTION(ob_inflatehandler) -{ - char *data; - int data_len; - long mode; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) { - RETURN_FALSE; - } - - http_ob_inflatehandler(data, data_len, &Z_STRVAL_P(return_value), (uint *) &Z_STRLEN_P(return_value), mode); - Z_TYPE_P(return_value) = Z_STRVAL_P(return_value) ? IS_STRING : IS_NULL; -} -/* }}} */ - -#endif /* HTTP_HAVE_ZLIB */ -/* }}} */ - -/* {{{ proto int http_support([int feature = 0]) - Check for feature that require external libraries. */ -PHP_FUNCTION(http_support) -{ - long feature = 0; - - RETVAL_LONG(0L); - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &feature)) { - RETVAL_LONG(http_support(feature)); - } -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_headers_api.c b/http_headers_api.c deleted file mode 100644 index 3091b63..0000000 --- a/http_headers_api.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#include "php_http.h" - -#include "ext/standard/url.h" -#include "ext/standard/php_string.h" - -#include "php_http_api.h" -#include "php_http_headers_api.h" - -#ifndef HTTP_DBG_NEG -# define HTTP_DBG_NEG 0 -#endif - -/* {{{ static void http_grab_response_headers(void *, void *) */ -static void http_grab_response_headers(void *data, void *arg TSRMLS_DC) -{ - phpstr_appendl(PHPSTR(arg), ((sapi_header_struct *)data)->header); - phpstr_appends(PHPSTR(arg), HTTP_CRLF); -} -/* }}} */ - -/* {{{ static int http_sort_q(const void *, const void *) */ -static int http_sort_q(const void *a, const void *b TSRMLS_DC) -{ - Bucket *f, *s; - zval result, *first, *second; - - f = *((Bucket **) a); - s = *((Bucket **) b); - - first = *((zval **) f->pData); - second= *((zval **) s->pData); - - if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) { - return 0; - } - return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0)); -} -/* }}} */ - -/* {{{ char *http_negotiate_language_func */ -char *_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC) -{ - zval **value; - HashPosition pos; - const char *dash_test; - - FOREACH_HASH_VAL(pos, supported, value) { -#if HTTP_DBG_NEG - fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test); -#endif - if (!strcasecmp(Z_STRVAL_PP(value), test)) { - return Z_STRVAL_PP(value); - } - } - - /* no distinct match found, so try primaries */ - if ((dash_test = strchr(test, '-'))) { - FOREACH_HASH_VAL(pos, supported, value) { - int len = dash_test - test; -#if HTTP_DBG_NEG - fprintf(stderr, "strncasecmp('%s', '%s', %d)\n", Z_STRVAL_PP(value), test, len); -#endif - if ( (!strncasecmp(Z_STRVAL_PP(value), test, len)) && - ( (Z_STRVAL_PP(value)[len] == '\0') || - (Z_STRVAL_PP(value)[len] == '-'))) { - *quality *= .9; - return Z_STRVAL_PP(value); - } - } - } - - return NULL; -} -/* }}} */ - -/* {{{ char *http_negotiate_default_func */ -char *_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC) -{ - zval **value; - HashPosition pos; - - FOREACH_HASH_VAL(pos, supported, value) { -#if HTTP_DBG_NEG - fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test); -#endif - if (!strcasecmp(Z_STRVAL_PP(value), test)) { - return Z_STRVAL_PP(value); - } - } - - return NULL; -} -/* }}} */ - -/* {{{ HashTable *http_negotiate_z(zval *, HashTable *, negotiate_func_t) */ -PHP_HTTP_API HashTable *_http_negotiate_z(zval *value, HashTable *supported, negotiate_func_t neg TSRMLS_DC) -{ - zval *accept = http_zsep(IS_STRING, value); - HashTable *result = NULL; - - if (Z_STRLEN_P(accept)) { - zval ex_arr, ex_del; - - INIT_PZVAL(&ex_del); - INIT_PZVAL(&ex_arr); - ZVAL_STRINGL(&ex_del, ",", 1, 0); - array_init(&ex_arr); - - php_explode(&ex_del, accept, &ex_arr, INT_MAX); - - if (zend_hash_num_elements(Z_ARRVAL(ex_arr)) > 0) { - int i = 0; - HashPosition pos; - zval **entry, array; - - INIT_PZVAL(&array); - array_init(&array); - - FOREACH_HASH_VAL(pos, Z_ARRVAL(ex_arr), entry) { - int ident_len; - double quality; - char *selected, *identifier, *freeme; - const char *separator; - -#if HTTP_DBG_NEG - fprintf(stderr, "Checking %s\n", Z_STRVAL_PP(entry)); -#endif - - if ((separator = strchr(Z_STRVAL_PP(entry), ';'))) { - const char *ptr = separator; - - while (*++ptr && !HTTP_IS_CTYPE(digit, *ptr) && '.' != *ptr); - - quality = zend_strtod(ptr, NULL); - identifier = estrndup(Z_STRVAL_PP(entry), ident_len = separator - Z_STRVAL_PP(entry)); - } else { - quality = 1000.0 - i++; - identifier = estrndup(Z_STRVAL_PP(entry), ident_len = Z_STRLEN_PP(entry)); - } - freeme = identifier; - - while (HTTP_IS_CTYPE(space, *identifier)) { - ++identifier; - --ident_len; - } - while (ident_len && HTTP_IS_CTYPE(space, identifier[ident_len - 1])) { - identifier[--ident_len] = '\0'; - } - - if ((selected = neg(identifier, &quality, supported TSRMLS_CC))) { - /* don't overwrite previously set with higher quality */ - if (!zend_hash_exists(Z_ARRVAL(array), selected, strlen(selected) + 1)) { - add_assoc_double(&array, selected, quality); - } - } - - efree(freeme); - } - - result = Z_ARRVAL(array); - zend_hash_sort(result, zend_qsort, http_sort_q, 0 TSRMLS_CC); - } - - zval_dtor(&ex_arr); - } - - zval_ptr_dtor(&accept); - - return result; -} -/* }}} */ - -/* {{{ HashTable *http_negotiate_q(const char *, HashTable *, negotiate_func_t) */ -PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *supported, negotiate_func_t neg TSRMLS_DC) -{ - zval *accept; - -#if HTTP_DBG_NEG - fprintf(stderr, "Reading header %s: ", header); -#endif - if (!(accept = http_get_server_var(header, 1))) { - return NULL; - } -#if HTTP_DBG_NEG - fprintf(stderr, "%s\n", Z_STRVAL_P(accept)); -#endif - - return http_negotiate_z(accept, supported, neg); -} -/* }}} */ - -/* {{{ http_range_status http_get_request_ranges(HashTable *ranges, size_t) */ -PHP_HTTP_API http_range_status _http_get_request_ranges(HashTable *ranges, size_t length TSRMLS_DC) -{ - zval *zrange; - char *range, c; - long begin = -1, end = -1, *ptr; - - if ( !(zrange = http_get_server_var("HTTP_RANGE", 1)) || - (size_t) Z_STRLEN_P(zrange) < lenof("bytes=") || strncmp(Z_STRVAL_P(zrange), "bytes=", lenof("bytes="))) { - return RANGE_NO; - } - range = Z_STRVAL_P(zrange) + lenof("bytes="); - ptr = &begin; - - do { - switch (c = *(range++)) { - case '0': - /* allow 000... - shall we? */ - if (*ptr != -10) { - *ptr *= 10; - } - break; - - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - /* - * If the value of the pointer is already set (non-negative) - * then multiply its value by ten and add the current value, - * else initialise the pointers value with the current value - * -- - * This let us recognize empty fields when validating the - * ranges, i.e. a "-10" for begin and "12345" for the end - * was the following range request: "Range: bytes=0-12345"; - * While a "-1" for begin and "12345" for the end would - * have been: "Range: bytes=-12345". - */ - if (*ptr > 0) { - *ptr *= 10; - *ptr += c - '0'; - } else { - *ptr = c - '0'; - } - break; - - case '-': - ptr = &end; - break; - - case ' ': - break; - - case 0: - case ',': - - if (length) { - /* validate ranges */ - switch (begin) { - /* "0-12345" */ - case -10: - switch (end) { - /* "0-" */ - case -1: - return RANGE_NO; - - /* "0-0" */ - case -10: - end = 0; - break; - - default: - if (length <= (size_t) end) { - return RANGE_ERR; - } - break; - } - begin = 0; - break; - - /* "-12345" */ - case -1: - /* "-", "-0" or overflow */ - if (end == -1 || end == -10 || length <= (size_t) end) { - return RANGE_ERR; - } - begin = length - end; - end = length - 1; - break; - - /* "12345-(xxx)" */ - default: - switch (end) { - /* "12345-0" */ - case -10: - return RANGE_ERR; - - /* "12345-" */ - case -1: - if (length <= (size_t) begin) { - return RANGE_ERR; - } - end = length - 1; - break; - - /* "12345-67890" */ - default: - if ( (length <= (size_t) begin) || - (length <= (size_t) end) || - (end < begin)) { - return RANGE_ERR; - } - break; - } - break; - } - } - { - zval *zentry; - MAKE_STD_ZVAL(zentry); - array_init(zentry); - add_index_long(zentry, 0, begin); - add_index_long(zentry, 1, end); - zend_hash_next_index_insert(ranges, &zentry, sizeof(zval *), NULL); - - begin = -1; - end = -1; - ptr = &begin; - } - break; - - default: - return RANGE_NO; - } - } while (c != 0); - - return RANGE_OK; -} -/* }}} */ - -/* {{{ STATUS http_parse_headers(char *, HashTable *, zend_bool) */ -PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, - http_info_callback callback_func, void **callback_data TSRMLS_DC) -{ - const char *colon = NULL, *line = NULL; - zval array; - - INIT_ZARR(array, headers); - - /* skip leading ws */ - while (HTTP_IS_CTYPE(space, *header)) ++header; - line = header; - -#define MORE_HEADERS (*(line-1) && !(*(line-1) == '\n' && (*line == '\n' || *line == '\r'))) - do { - int value_len = 0; - - switch (*line++) { - case ':': - if (!colon) { - colon = line - 1; - } - break; - - case 0: - --value_len; /* we don't have CR so value length is one char less */ - case '\n': - if ((!*(line - 1)) || ((*line != ' ') && (*line != '\t'))) { - http_info i; - - if (SUCCESS == http_info_parse(header, &i)) { - /* response/request line */ - callback_func(callback_data, &headers, &i TSRMLS_CC); - http_info_dtor(&i); - Z_ARRVAL(array) = headers; - } else if (colon) { - /* "header: value" pair */ - if (header != colon) { - int keylen = colon - header; - const char *key = header; - - /* skip leading ws */ - while (keylen && HTTP_IS_CTYPE(space, *key)) --keylen, ++key; - /* skip trailing ws */ - while (keylen && HTTP_IS_CTYPE(space, key[keylen - 1])) --keylen; - - if (keylen > 0) { - zval **previous = NULL; - char *value; - char *keydup = estrndup(key, keylen); - - if (prettify) { - keydup = pretty_key(keydup, keylen, 1, 1); - } - - value_len += line - colon - 1; - - /* skip leading ws */ - while (HTTP_IS_CTYPE(space, *(++colon))) --value_len; - /* skip trailing ws */ - while (HTTP_IS_CTYPE(space, colon[value_len - 1])) --value_len; - - if (value_len > 0) { - value = estrndup(colon, value_len); - } else { - value = estrdup(""); - value_len = 0; - } - - /* if we already have got such a header make an array of those */ - if (SUCCESS == zend_hash_find(headers, keydup, keylen + 1, (void *) &previous)) { - /* convert to array */ - if (Z_TYPE_PP(previous) != IS_ARRAY) { - convert_to_array(*previous); - } - add_next_index_stringl(*previous, value, value_len, 0); - } else { - add_assoc_stringl(&array, keydup, value, value_len, 0); - } - efree(keydup); - } else { - /* empty key (" : ...") */ - return FAILURE; - } - } else { - /* empty key (": ...") */ - return FAILURE; - } - } else if (MORE_HEADERS) { - /* a line without a colon */ - return FAILURE; - } - colon = NULL; - value_len = 0; - header += line - header; - } - break; - } - } while (MORE_HEADERS); - - return SUCCESS; -} -/* }}} */ - -/* {{{ void http_get_request_headers(HashTable *) */ -PHP_HTTP_API void _http_get_request_headers(HashTable *headers TSRMLS_DC) -{ - HashKey key = initHashKey(0); - zval **hsv, **header; - HashPosition pos; - - if (!HTTP_G->request.headers) { - ALLOC_HASHTABLE(HTTP_G->request.headers); - zend_hash_init(HTTP_G->request.headers, 0, NULL, ZVAL_PTR_DTOR, 0); - -#ifdef ZEND_ENGINE_2 - zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC); -#endif - - if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv) && Z_TYPE_PP(hsv) == IS_ARRAY) { - FOREACH_KEY(pos, *hsv, key) { - if (key.type == HASH_KEY_IS_STRING && key.len > 6 && !strncmp(key.str, "HTTP_", 5)) { - key.len -= 5; - key.str = pretty_key(estrndup(key.str + 5, key.len - 1), key.len - 1, 1, 1); - - zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos); - ZVAL_ADDREF(*header); - zend_hash_add(HTTP_G->request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL); - - efree(key.str); - } - } - } - } - - if (headers) { - zend_hash_copy(headers, HTTP_G->request.headers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - } -} -/* }}} */ - -/* {{{ STATUS http_get_response_headers(HashTable *) */ -PHP_HTTP_API STATUS _http_get_response_headers(HashTable *headers_ht TSRMLS_DC) -{ - STATUS status; - phpstr headers; - - phpstr_init(&headers); - zend_llist_apply_with_argument(&SG(sapi_headers).headers, http_grab_response_headers, &headers TSRMLS_CC); - phpstr_fix(&headers); - - status = http_parse_headers_ex(PHPSTR_VAL(&headers), headers_ht, 1); - phpstr_dtor(&headers); - - return status; -} -/* }}} */ - -/* {{{ zend_bool http_match_request_header(char *, char *) */ -PHP_HTTP_API zend_bool _http_match_request_header_ex(const char *header, const char *value, zend_bool match_case TSRMLS_DC) -{ - char *name; - uint name_len = strlen(header); - zend_bool result = 0; - zval **data, *zvalue; - - http_get_request_headers(NULL); - name = pretty_key(estrndup(header, name_len), name_len, 1, 1); - if (SUCCESS == zend_hash_find(HTTP_G->request.headers, name, name_len+1, (void *) &data)) { - zvalue = http_zsep(IS_STRING, *data); - result = (match_case ? strcmp(Z_STRVAL_P(zvalue), value) : strcasecmp(Z_STRVAL_P(zvalue), value)) ? 0 : 1; - zval_ptr_dtor(&zvalue); - } - efree(name); - - return result; -} -/* }}} */ - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_inflatestream_object.c b/http_inflatestream_object.c deleted file mode 100644 index 3340e4c..0000000 --- a/http_inflatestream_object.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_ZLIB -#include "php_http.h" - -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_ZLIB) - -#include "php_http_api.h" -#include "php_http_encoding_api.h" -#include "php_http_exception_object.h" -#include "php_http_inflatestream_object.h" - -#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpInflateStream, method, 0, req_args) -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpInflateStream, method, 0) -#define HTTP_INFLATE_ME(method, visibility) PHP_ME(HttpInflateStream, method, HTTP_ARGS(HttpInflateStream, method), visibility) - -HTTP_BEGIN_ARGS(__construct, 0) - HTTP_ARG_VAL(flags, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(factory, 0) - HTTP_ARG_VAL(flags, 0) - HTTP_ARG_VAL(class_name, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(update, 1) - HTTP_ARG_VAL(data, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(flush, 0) - HTTP_ARG_VAL(data, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(finish, 0) - HTTP_ARG_VAL(data, 0) -HTTP_END_ARGS; - -#define THIS_CE http_inflatestream_object_ce -zend_class_entry *http_inflatestream_object_ce; -zend_function_entry http_inflatestream_object_fe[] = { - HTTP_INFLATE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - HTTP_INFLATE_ME(update, ZEND_ACC_PUBLIC) - HTTP_INFLATE_ME(flush, ZEND_ACC_PUBLIC) - HTTP_INFLATE_ME(finish, ZEND_ACC_PUBLIC) - - HTTP_INFLATE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - - EMPTY_FUNCTION_ENTRY -}; -static zend_object_handlers http_inflatestream_object_handlers; - -PHP_MINIT_FUNCTION(http_inflatestream_object) -{ - HTTP_REGISTER_CLASS_EX(HttpInflateStream, http_inflatestream_object, NULL, 0); - http_inflatestream_object_handlers.clone_obj = _http_inflatestream_object_clone_obj; - -#ifndef WONKY - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_NONE")-1, HTTP_ENCODING_STREAM_FLUSH_NONE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_SYNC")-1, HTTP_ENCODING_STREAM_FLUSH_SYNC TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("FLUSH_FULL")-1, HTTP_ENCODING_STREAM_FLUSH_FULL TSRMLS_CC); -#endif - - return SUCCESS; -} - -zend_object_value _http_inflatestream_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return http_inflatestream_object_new_ex(ce, NULL, NULL); -} - -zend_object_value _http_inflatestream_object_new_ex(zend_class_entry *ce, http_encoding_stream *s, http_inflatestream_object **ptr TSRMLS_DC) -{ - zend_object_value ov; - http_inflatestream_object *o; - - o = ecalloc(1, sizeof(http_inflatestream_object)); - o->zo.ce = ce; - - if (ptr) { - *ptr = o; - } - - if (s) { - o->stream = s; - } - -#ifdef ZEND_ENGINE_2_4 - zend_object_std_init(o, ce TSRMLS_CC); - object_properties_init(o, ce); -#else - ALLOC_HASHTABLE(OBJ_PROP(o)); - zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); -#endif - - ov.handle = putObject(http_inflatestream_object, o); - ov.handlers = &http_inflatestream_object_handlers; - - return ov; -} - -zend_object_value _http_inflatestream_object_clone_obj(zval *this_ptr TSRMLS_DC) -{ - http_encoding_stream *s; - zend_object_value new_ov; - http_inflatestream_object *new_obj = NULL; - getObject(http_inflatestream_object, old_obj); - - s = ecalloc(1, sizeof(http_encoding_stream)); - s->flags = old_obj->stream->flags; - inflateCopy(&s->stream, &old_obj->stream->stream); - s->stream.opaque = phpstr_dup(s->stream.opaque); - - new_ov = http_inflatestream_object_new_ex(old_obj->zo.ce, s, &new_obj); - zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); - - return new_ov; -} - -void _http_inflatestream_object_free(zend_object *object TSRMLS_DC) -{ - http_inflatestream_object *o = (http_inflatestream_object *) object; - - if (o->stream) { - http_encoding_inflate_stream_free(&o->stream); - } - freeObject(o); -} - -/* {{{ proto void HttpInflateStream::__construct([int flags = 0]) - Creates a new HttpInflateStream object instance. */ -PHP_METHOD(HttpInflateStream, __construct) -{ - long flags = 0; - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags)) { - getObject(http_inflatestream_object, obj); - - if (!obj->stream) { - obj->stream = http_encoding_inflate_stream_init(NULL, flags & 0x0fffffff); - } else { - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "HttpInflateStream cannot be initialized twice"); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto HttpInflateStream HttpInflateStream::factory([int flags[, string class = "HttpInflateStream"]]) - Creates a new HttpInflateStream object instance. */ -PHP_METHOD(HttpInflateStream, factory) -{ - long flags = 0; - char *cn = NULL; - int cl = 0; - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &flags, &cn, &cl)) { - zend_object_value ov; - http_encoding_stream *s = http_encoding_inflate_stream_init(NULL, flags & 0x0fffffff); - - if (SUCCESS == http_object_new(&ov, cn, cl, _http_inflatestream_object_new_ex, http_inflatestream_object_ce, s, NULL)) { - RETVAL_OBJVAL(ov, 0); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto string HttpInflateStream::update(string data) - Passes more data through the inflate stream. */ -PHP_METHOD(HttpInflateStream, update) -{ - int data_len; - size_t decoded_len = 0; - char *data, *decoded = NULL; - getObject(http_inflatestream_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len)) { - RETURN_FALSE; - } - - if (!data_len) { - RETURN_STRING("", 1); - } - - if (!obj->stream && !(obj->stream = http_encoding_inflate_stream_init(NULL, 0))) { - RETURN_FALSE; - } - - if (SUCCESS == http_encoding_inflate_stream_update(obj->stream, data, data_len, &decoded, &decoded_len)) { - RETURN_STRINGL(decoded, decoded_len, 0); - } else { - RETURN_FALSE; - } -} -/* }}} */ - -/* {{{ proto string HttpInflateStream::flush([string data]) - Flush the inflate stream. */ -PHP_METHOD(HttpInflateStream, flush) -{ - int data_len = 0; - size_t decoded_len = 0; - char *decoded = NULL, *data = NULL; - getObject(http_inflatestream_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) { - RETURN_FALSE; - } - - if (!obj->stream && !(obj->stream = http_encoding_inflate_stream_init(NULL, 0))) { - RETURN_FALSE; - } - - /* flushing the inflate stream is a no-op */ - if (!data_len) { - RETURN_STRINGL("", 0, 1); - } else if (SUCCESS == http_encoding_inflate_stream_update(obj->stream, data, data_len, &decoded, &decoded_len)) { - RETURN_STRINGL(decoded, decoded_len, 0); - } else { - RETURN_FALSE; - } -} -/* }}} */ - -/* {{{ proto string HttpInflateStream::finish([string data]) - Finalizes the inflate stream. The inflate stream can be reused after finalizing. */ -PHP_METHOD(HttpInflateStream, finish) -{ - int data_len = 0; - size_t updated_len = 0, decoded_len = 0; - char *updated = NULL, *decoded = NULL, *data = NULL; - getObject(http_inflatestream_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &data, &data_len)) { - RETURN_FALSE; - } - - if (!obj->stream && !(obj->stream = http_encoding_inflate_stream_init(NULL, 0))) { - RETURN_FALSE; - } - - if (data_len) { - if (SUCCESS != http_encoding_inflate_stream_update(obj->stream, data, data_len, &updated, &updated_len)) { - RETURN_FALSE; - } - } - - if (SUCCESS == http_encoding_inflate_stream_finish(obj->stream, &decoded, &decoded_len)) { - if (updated_len) { - updated = erealloc(updated, updated_len + decoded_len + 1); - updated[updated_len + decoded_len] = '\0'; - memcpy(updated + updated_len, decoded, decoded_len); - STR_FREE(decoded); - updated_len += decoded_len; - RETVAL_STRINGL(updated, updated_len, 0); - } else if (decoded) { - STR_FREE(updated); - RETVAL_STRINGL(decoded, decoded_len, 0); - } else { - RETVAL_NULL(); - } - } else { - STR_FREE(updated); - RETVAL_FALSE; - } - - http_encoding_inflate_stream_dtor(obj->stream); - http_encoding_inflate_stream_init(obj->stream, obj->stream->flags); -} -/* }}} */ - -#endif /* ZEND_ENGINE_2 && HTTP_HAVE_ZLIB*/ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_info_api.c b/http_info_api.c deleted file mode 100644 index 358b5bf..0000000 --- a/http_info_api.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "php_http.h" - -#include "php_http_api.h" -#include "php_http_info_api.h" - -PHP_HTTP_API void _http_info_default_callback(void **nothing, HashTable **headers, http_info *info TSRMLS_DC) -{ - zval array; - - INIT_ZARR(array, *headers); - - switch (info->type) { - case IS_HTTP_REQUEST: - add_assoc_string(&array, "Request Method", HTTP_INFO(info).request.method, 1); - add_assoc_string(&array, "Request Url", HTTP_INFO(info).request.url, 1); - break; - - case IS_HTTP_RESPONSE: - add_assoc_long(&array, "Response Code", (long) HTTP_INFO(info).response.code); - if (HTTP_INFO(info).response.status) { - add_assoc_string(&array, "Response Status", HTTP_INFO(info).response.status, 1); - } - break; - } -} - -PHP_HTTP_API void _http_info_dtor(http_info *i) -{ - switch (i->type) { - case IS_HTTP_REQUEST: - STR_SET(HTTP_INFO(i).request.method, NULL); - STR_SET(HTTP_INFO(i).request.url, NULL); - break; - - case IS_HTTP_RESPONSE: - STR_SET(HTTP_INFO(i).response.status, NULL); - break; - - default: - break; - } -} - -PHP_HTTP_API STATUS _http_info_parse_ex(const char *pre_header, http_info *info, zend_bool silent TSRMLS_DC) -{ - const char *end, *http; - - /* sane parameter */ - if ((!pre_header) || (!*pre_header)) { - return FAILURE; - } - - /* where's the end of the line */ - if (!(end = http_locate_eol(pre_header, NULL))) { - end = pre_header + strlen(pre_header); - } - - /* there must be HTTP/1.x in the line */ - if (!(http = http_locate_str(pre_header, end - pre_header, "HTTP/1.", lenof("HTTP/1.")))) { - return FAILURE; - } - - /* and nothing than SPACE or NUL after HTTP/1.x */ - if ( (!HTTP_IS_CTYPE(digit, http[lenof("HTTP/1.")])) || - (http[lenof("HTTP/1.1")] && (!HTTP_IS_CTYPE(space, http[lenof("HTTP/1.1")])))) { - if (!silent) { - http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Invalid HTTP/1.x protocol identification"); - } - return FAILURE; - } - -#if 0 - { - char *line = estrndup(pre_header, end - pre_header); - fprintf(stderr, "http_parse_info('%s')\n", line); - efree(line); - } -#endif - - info->http.version = zend_strtod(http + lenof("HTTP/"), NULL); - - /* is response */ - if (pre_header == http) { - char *status = NULL; - const char *code = http + sizeof("HTTP/1.1"); - - info->type = IS_HTTP_RESPONSE; - while (' ' == *code) ++code; - if (code && end > code) { - HTTP_INFO(info).response.code = strtol(code, &status, 10); - } else { - HTTP_INFO(info).response.code = 0; - } - if (status && end > status) { - while (' ' == *status) ++status; - HTTP_INFO(info).response.status = estrndup(status, end - status); - } else { - HTTP_INFO(info).response.status = NULL; - } - - return SUCCESS; - } - - /* is request */ - else if (!http[lenof("HTTP/1.x")] || http[lenof("HTTP/1.x")] == '\r' || http[lenof("HTTP/1.x")] == '\n') { - const char *url = strchr(pre_header, ' '); - - info->type = IS_HTTP_REQUEST; - if (url && http > url) { - HTTP_INFO(info).request.method = estrndup(pre_header, url - pre_header); - while (' ' == *url) ++url; - while (' ' == *(http-1)) --http; - if (http > url) { - HTTP_INFO(info).request.url = estrndup(url, http - url); - } else { - efree(HTTP_INFO(info).request.method); - return FAILURE; - } - } else { - HTTP_INFO(info).request.method = NULL; - HTTP_INFO(info).request.url = NULL; - } - - return SUCCESS; - } - - /* some darn header containing HTTP/1.x */ - else { - return FAILURE; - } -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_message_api.c b/http_message_api.c deleted file mode 100644 index 007437c..0000000 --- a/http_message_api.c +++ /dev/null @@ -1,739 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#define HTTP_WANT_CURL -#define HTTP_WANT_ZLIB -#include "php_http.h" - -#include "php_http_api.h" -#include "php_http_encoding_api.h" -#include "php_http_headers_api.h" -#include "php_http_message_api.h" -#include "php_http_request_api.h" -#include "php_http_send_api.h" -#include "php_http_url_api.h" - -#define http_message_info_callback _http_message_info_callback -static void _http_message_info_callback(http_message **message, HashTable **headers, http_info *info TSRMLS_DC) -{ - http_message *old = *message; - - /* advance message */ - if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) { - (*message) = http_message_new(); - (*message)->parent = old; - (*headers) = &((*message)->hdrs); - } - - http_message_set_info(*message, info); -} - -#define http_message_init_type _http_message_init_type -static inline void _http_message_init_type(http_message *message, http_message_type type) -{ - message->http.version = .0; - - switch (message->type = type) { - case HTTP_MSG_RESPONSE: - message->http.info.response.code = 0; - message->http.info.response.status = NULL; - break; - - case HTTP_MSG_REQUEST: - message->http.info.request.method = NULL; - message->http.info.request.url = NULL; - break; - - case HTTP_MSG_NONE: - default: - break; - } -} - -PHP_HTTP_API http_message *_http_message_init_ex(http_message *message, http_message_type type ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) -{ - if (!message) { - message = ecalloc_rel(1, sizeof(http_message)); - } - - http_message_init_type(message, type); - message->parent = NULL; - phpstr_init(&message->body); - zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0); - - return message; -} - -PHP_HTTP_API http_message *_http_message_init_env(http_message *message, http_message_type type TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) -{ - int free_msg; - http_info inf; - zval *sval, tval; - char *body_str; - size_t body_len; - - if ((free_msg = !message)) { - message = http_message_init_rel(NULL, HTTP_MSG_NONE); - } - - memset(&inf, 0, sizeof(http_info)); - switch (inf.type = type) { - case HTTP_MSG_REQUEST: - if ((sval = http_get_server_var("SERVER_PROTOCOL", 1)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) { - inf.http.version = zend_strtod(Z_STRVAL_P(sval) + lenof("HTTP/"), NULL); - } else { - inf.http.version = 1.1; - } - if ((sval = http_get_server_var("REQUEST_METHOD", 1))) { - inf.http.info.request.method = estrdup(Z_STRVAL_P(sval)); - } - if ((sval = http_get_server_var("REQUEST_URI", 1))) { - inf.http.info.request.url = estrdup(Z_STRVAL_P(sval)); - } - - http_message_set_info(message, &inf); - http_get_request_headers(&message->hdrs); - if (SUCCESS == http_get_request_body_ex(&body_str, &body_len, 0)) { - phpstr_from_string_ex(&message->body, body_str, body_len); - } - break; - - case HTTP_MSG_RESPONSE: - if (!SG(sapi_headers).http_status_line || SUCCESS != http_info_parse_ex(SG(sapi_headers).http_status_line, &inf, 0)) { - inf.http.version = 1.1; - inf.http.info.response.code = 200; - inf.http.info.response.status = estrdup("Ok"); - } - - http_message_set_info(message, &inf); - http_get_response_headers(&message->hdrs); -#ifdef PHP_OUTPUT_NEWAPI - if (SUCCESS == php_output_get_contents(&tval TSRMLS_CC)) { -#else - if (SUCCESS == php_ob_get_buffer(&tval TSRMLS_CC)) { -#endif - message->body.data = Z_STRVAL(tval); - message->body.used = Z_STRLEN(tval); - message->body.free = 1; /* "\0" */ - } - break; - - default: - if (free_msg) { - http_message_free(&message); - } else { - message = NULL; - } - break; - } - http_info_dtor(&inf); - - return message; -} - -PHP_HTTP_API void _http_message_set_type(http_message *message, http_message_type type) -{ - /* just act if different */ - if (type != message->type) { - - /* free request info */ - switch (message->type) { - case HTTP_MSG_REQUEST: - STR_FREE(message->http.info.request.method); - STR_FREE(message->http.info.request.url); - break; - - case HTTP_MSG_RESPONSE: - STR_FREE(message->http.info.response.status); - break; - - default: - break; - } - - /* init */ - http_message_init_type(message, type); - } -} - -PHP_HTTP_API void _http_message_set_info(http_message *message, http_info *info) -{ - http_message_set_type(message, info->type); - message->http.version = info->http.version; - switch (message->type) { - case IS_HTTP_REQUEST: - STR_SET(HTTP_INFO(message).request.url, HTTP_INFO(info).request.url ? estrdup(HTTP_INFO(info).request.url) : NULL); - STR_SET(HTTP_INFO(message).request.method, HTTP_INFO(info).request.method ? estrdup(HTTP_INFO(info).request.method) : NULL); - break; - - case IS_HTTP_RESPONSE: - HTTP_INFO(message).response.code = HTTP_INFO(info).response.code; - STR_SET(HTTP_INFO(message).response.status, HTTP_INFO(info).response.status ? estrdup(HTTP_INFO(info).response.status) : NULL); - break; - - default: - break; - } -} - -#define http_message_body_parse(m, ms, ml, c) _http_message_body_parse((m), (ms), (ml), (c) TSRMLS_CC) -static inline void _http_message_body_parse(http_message *msg, const char *message, size_t message_length, const char **continue_at TSRMLS_DC) -{ - zval *c; - size_t remaining; - const char *body; - - *continue_at = NULL; - if ((body = http_locate_body(message))) { - remaining = message + message_length - body; - - if ((c = http_message_header(msg, "Transfer-Encoding"))) { - if (strstr(Z_STRVAL_P(c), "chunked")) { - /* message has chunked transfer encoding */ - char *decoded; - size_t decoded_len; - - /* decode and replace Transfer-Encoding with Content-Length header */ - if ((*continue_at = http_encoding_dechunk(body, message + message_length - body, &decoded, &decoded_len))) { - zval *len; - char *tmp; - int tmp_len; - - tmp_len = (int) spprintf(&tmp, 0, "%zu", decoded_len); - MAKE_STD_ZVAL(len); - ZVAL_STRINGL(len, tmp, tmp_len, 0); - - ZVAL_ADDREF(c); - zend_hash_update(&msg->hdrs, "X-Original-Transfer-Encoding", sizeof("X-Original-Transfer-Encoding"), (void *) &c, sizeof(zval *), NULL); - zend_hash_del(&msg->hdrs, "Transfer-Encoding", sizeof("Transfer-Encoding")); - zend_hash_del(&msg->hdrs, "Content-Length", sizeof("Content-Length")); - zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &len, sizeof(zval *), NULL); - - phpstr_from_string_ex(PHPSTR(msg), decoded, decoded_len); - efree(decoded); - } - } - zval_ptr_dtor(&c); - } - - if (!*continue_at && (c = http_message_header(msg, "Content-Length"))) { - /* message has content-length header */ - ulong len = strtoul(Z_STRVAL_P(c), NULL, 10); - if (len > remaining) { - http_error_ex(HE_NOTICE, HTTP_E_MALFORMED_HEADERS, "The Content-Length header pretends a larger body than actually received (expected %lu bytes; got %lu bytes)", len, remaining); - len = remaining; - } - phpstr_from_string_ex(PHPSTR(msg), body, len); - *continue_at = body + len; - zval_ptr_dtor(&c); - } - - if (!*continue_at && (c = http_message_header(msg, "Content-Range"))) { - /* message has content-range header */ - ulong total = 0, start = 0, end = 0, len = 0; - - if (!strncasecmp(Z_STRVAL_P(c), "bytes", lenof("bytes")) && - ( Z_STRVAL_P(c)[lenof("bytes")] == ':' || - Z_STRVAL_P(c)[lenof("bytes")] == ' ' || - Z_STRVAL_P(c)[lenof("bytes")] == '=')) { - char *total_at = NULL, *end_at = NULL; - char *start_at = Z_STRVAL_P(c) + sizeof("bytes"); - - start = strtoul(start_at, &end_at, 10); - if (end_at) { - end = strtoul(end_at + 1, &total_at, 10); - if (total_at && strncmp(total_at + 1, "*", 1)) { - total = strtoul(total_at + 1, NULL, 10); - } - if ((len = (end + 1 - start)) > remaining) { - http_error_ex(HE_NOTICE, HTTP_E_MALFORMED_HEADERS, "The Content-Range header pretends a larger body than actually received (expected %lu bytes; got %lu bytes)", len, remaining); - len = remaining; - } - if (end >= start && (!total || end < total)) { - phpstr_from_string_ex(PHPSTR(msg), body, len); - *continue_at = body + len; - } - } - } - - if (!*continue_at) { - http_error_ex(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Invalid Content-Range header: %s", Z_STRVAL_P(c)); - } - zval_ptr_dtor(&c); - } - - if (!*continue_at) { - /* no headers that indicate content length */ - if (HTTP_MSG_TYPE(RESPONSE, msg)) { - phpstr_from_string_ex(PHPSTR(msg), body, remaining); - } else { - *continue_at = body; - } - } - -#ifdef HTTP_HAVE_ZLIB - /* check for compressed data */ - if ((c = http_message_header(msg, "Content-Encoding"))) { - char *decoded = NULL; - size_t decoded_len = 0; - - if ( !strcasecmp(Z_STRVAL_P(c), "gzip") || - !strcasecmp(Z_STRVAL_P(c), "x-gzip") || - !strcasecmp(Z_STRVAL_P(c), "deflate")) { - http_encoding_inflate(PHPSTR_VAL(msg), PHPSTR_LEN(msg), &decoded, &decoded_len); - } - - if (decoded) { - zval *len, **original_len; - char *tmp; - int tmp_len; - - tmp_len = (int) spprintf(&tmp, 0, "%zu", decoded_len); - MAKE_STD_ZVAL(len); - ZVAL_STRINGL(len, tmp, tmp_len, 0); - - ZVAL_ADDREF(c); - zend_hash_update(&msg->hdrs, "X-Original-Content-Encoding", sizeof("X-Original-Content-Encoding"), (void *) &c, sizeof(zval *), NULL); - zend_hash_del(&msg->hdrs, "Content-Encoding", sizeof("Content-Encoding")); - if (SUCCESS == zend_hash_find(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &original_len)) { - ZVAL_ADDREF(*original_len); - zend_hash_update(&msg->hdrs, "X-Original-Content-Length", sizeof("X-Original-Content-Length"), (void *) original_len, sizeof(zval *), NULL); - zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &len, sizeof(zval *), NULL); - } else { - zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void *) &len, sizeof(zval *), NULL); - } - - phpstr_dtor(PHPSTR(msg)); - PHPSTR(msg)->data = decoded; - PHPSTR(msg)->used = decoded_len; - PHPSTR(msg)->free = 1; - } - - zval_ptr_dtor(&c); - } -#endif /* HTTP_HAVE_ZLIB */ - } -} - -PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char *message, size_t message_length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - const char *continue_at; - zend_bool free_msg = msg ? 0 : 1; - - if ((!message) || (message_length < HTTP_MSG_MIN_SIZE)) { - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Empty or too short HTTP message: '%s'", message); - return NULL; - } - - msg = http_message_init_rel(msg, 0); - - if (SUCCESS != http_parse_headers_cb(message, &msg->hdrs, 1, (http_info_callback) http_message_info_callback, (void *) &msg)) { - if (free_msg) { - http_message_free(&msg); - } - http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Failed to parse message headers"); - return NULL; - } - - http_message_body_parse(msg, message, message_length, &continue_at); - - /* check for following messages */ - if (continue_at && (continue_at < (message + message_length))) { - while (HTTP_IS_CTYPE(space, *continue_at)) ++continue_at; - if (continue_at < (message + message_length)) { - http_message *next = NULL, *most = NULL; - - /* set current message to parent of most parent following messages and return deepest */ - if ((most = next = http_message_parse_rel(NULL, continue_at, message + message_length - continue_at))) { - while (most->parent) most = most->parent; - most->parent = msg; - msg = next; - } - } - } - - return msg; -} - -PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length) -{ - phpstr str; - HashKey key = initHashKey(0); - zval **header; - char *data; - HashPosition pos1; - - phpstr_init_ex(&str, 4096, 0); - - switch (msg->type) { - case HTTP_MSG_REQUEST: - phpstr_appendf(&str, HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, HTTP_CRLF)); - break; - - case HTTP_MSG_RESPONSE: - phpstr_appendf(&str, HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, HTTP_CRLF)); - break; - - case HTTP_MSG_NONE: - default: - break; - } - - FOREACH_HASH_KEYVAL(pos1, &msg->hdrs, key, header) { - if (key.type == HASH_KEY_IS_STRING) { - HashPosition pos2; - zval **single_header; - - switch (Z_TYPE_PP(header)) { - case IS_BOOL: - phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_BVAL_PP(header)?"true":"false"); - break; - - case IS_LONG: - phpstr_appendf(&str, "%s: %ld" HTTP_CRLF, key.str, Z_LVAL_PP(header)); - break; - - case IS_DOUBLE: - phpstr_appendf(&str, "%s: %f" HTTP_CRLF, key.str, Z_DVAL_PP(header)); - break; - - case IS_STRING: - phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_STRVAL_PP(header)); - break; - - case IS_ARRAY: - FOREACH_VAL(pos2, *header, single_header) { - switch (Z_TYPE_PP(single_header)) { - case IS_BOOL: - phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_BVAL_PP(single_header)?"true":"false"); - break; - - case IS_LONG: - phpstr_appendf(&str, "%s: %ld" HTTP_CRLF, key.str, Z_LVAL_PP(single_header)); - break; - - case IS_DOUBLE: - phpstr_appendf(&str, "%s: %f" HTTP_CRLF, key.str, Z_DVAL_PP(single_header)); - break; - - case IS_STRING: - phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_STRVAL_PP(single_header)); - break; - } - } - break; - } - } - } - - if (PHPSTR_LEN(msg)) { - phpstr_appends(&str, HTTP_CRLF); - phpstr_append(&str, PHPSTR_VAL(msg), PHPSTR_LEN(msg)); - phpstr_appends(&str, HTTP_CRLF); - } - - data = phpstr_data(&str, string, length); - if (!string) { - efree(data); - } - - phpstr_dtor(&str); -} - -PHP_HTTP_API void _http_message_serialize(http_message *message, char **string, size_t *length) -{ - char *buf; - size_t len; - phpstr str; - - phpstr_init(&str); - - do { - http_message_tostring(message, &buf, &len); - phpstr_prepend(&str, buf, len); - efree(buf); - } while ((message = message->parent)); - - buf = phpstr_data(&str, string, length); - if (!string) { - efree(buf); - } - - phpstr_dtor(&str); -} - -PHP_HTTP_API http_message *_http_message_reverse(http_message *msg) -{ - int i, c; - - http_message_count(c, msg); - - if (c > 1) { - http_message *tmp = msg, **arr = ecalloc(c, sizeof(http_message *)); - - for (i = 0; i < c; ++i) { - arr[i] = tmp; - tmp = tmp->parent; - } - arr[0]->parent = NULL; - for (i = 0; i < c-1; ++i) { - arr[i+1]->parent = arr[i]; - } - - msg = arr[c-1]; - efree(arr); - } - - return msg; -} - -PHP_HTTP_API http_message *_http_message_interconnect(http_message *m1, http_message *m2) -{ - if (m1 && m2) { - int i = 0, c1, c2; - http_message *t1 = m1, *t2 = m2, *p1, *p2; - - http_message_count(c1, m1); - http_message_count(c2, m2); - - while (i++ < (c1 - c2)) { - t1 = t1->parent; - } - while (i++ <= c1) { - p1 = t1->parent; - p2 = t2->parent; - t1->parent = t2; - t2->parent = p1; - t1 = p1; - t2 = p2; - } - } else if (!m1 && m2) { - m1 = m2; - } - return m1; -} - -PHP_HTTP_API void _http_message_tostruct_recursive(http_message *msg, zval *obj TSRMLS_DC) -{ - zval strct; - zval *headers; - - INIT_ZARR(strct, HASH_OF(obj)); - - add_assoc_long(&strct, "type", msg->type); - add_assoc_double(&strct, "httpVersion", msg->http.version); - switch (msg->type) - { - case HTTP_MSG_RESPONSE: - add_assoc_long(&strct, "responseCode", msg->http.info.response.code); - add_assoc_string(&strct, "responseStatus", STR_PTR(msg->http.info.response.status), 1); - break; - - case HTTP_MSG_REQUEST: - add_assoc_string(&strct, "requestMethod", STR_PTR(msg->http.info.request.method), 1); - add_assoc_string(&strct, "requestUrl", STR_PTR(msg->http.info.request.url), 1); - break; - - case HTTP_MSG_NONE: - /* avoid compiler warning */ - break; - } - - MAKE_STD_ZVAL(headers); - array_init(headers); - zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - add_assoc_zval(&strct, "headers", headers); - - add_assoc_stringl(&strct, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg), 1); - - if (msg->parent) { - zval *parent; - - MAKE_STD_ZVAL(parent); - if (Z_TYPE_P(obj) == IS_ARRAY) { - array_init(parent); - } else { - object_init(parent); - } - add_assoc_zval(&strct, "parentMessage", parent); - http_message_tostruct_recursive(msg->parent, parent); - } else { - add_assoc_null(&strct, "parentMessage"); - } -} - -PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC) -{ - STATUS rs = FAILURE; - - switch (message->type) { - case HTTP_MSG_RESPONSE: - { - HashKey key = initHashKey(0); - zval **val; - HashPosition pos; - - FOREACH_HASH_KEYVAL(pos, &message->hdrs, key, val) { - if (key.type == HASH_KEY_IS_STRING) { - http_send_header_zval_ex(key.str, key.len-1, val, 1); - } - } - rs = SUCCESS == http_send_status(message->http.info.response.code) && - SUCCESS == http_send_data(PHPSTR_VAL(message), PHPSTR_LEN(message)) ? - SUCCESS : FAILURE; - break; - } - - case HTTP_MSG_REQUEST: - { -#ifdef HTTP_HAVE_CURL - char *uri = NULL; - http_request request; - zval **zhost, *options, *headers; - - MAKE_STD_ZVAL(options); - MAKE_STD_ZVAL(headers); - array_init(options); - array_init(headers); - zend_hash_copy(Z_ARRVAL_P(headers), &message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - add_assoc_zval(options, "headers", headers); - - /* check host header */ - if (SUCCESS == zend_hash_find(&message->hdrs, "Host", sizeof("Host"), (void *) &zhost) && Z_TYPE_PP(zhost) == IS_STRING) { - char *colon = NULL; - php_url parts, *url = php_url_parse(message->http.info.request.url); - - memset(&parts, 0, sizeof(php_url)); - - /* check for port */ - if ((colon = strchr(Z_STRVAL_PP(zhost), ':'))) { - parts.port = atoi(colon + 1); - parts.host = estrndup(Z_STRVAL_PP(zhost), (Z_STRVAL_PP(zhost) - colon - 1)); - } else { - parts.host = estrndup(Z_STRVAL_PP(zhost), Z_STRLEN_PP(zhost)); - } - - http_build_url(HTTP_URL_REPLACE, url, &parts, NULL, &uri, NULL); - php_url_free(url); - efree(parts.host); - } else { - uri = http_absolute_url(message->http.info.request.url); - } - - if ((request.meth = http_request_method_exists(1, 0, message->http.info.request.method))) { - http_request_body body; - - http_request_init_ex(&request, NULL, request.meth, uri); - request.body = http_request_body_init_ex(&body, HTTP_REQUEST_BODY_CSTRING, PHPSTR_VAL(message), PHPSTR_LEN(message), 0); - if (SUCCESS == (rs = http_request_prepare(&request, Z_ARRVAL_P(options)))) { - http_request_exec(&request); - } - http_request_dtor(&request); - } else { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, - "Cannot send HttpMessage. Request method %s not supported", - message->http.info.request.method); - } - efree(uri); - zval_ptr_dtor(&options); -#else - http_error(HE_WARNING, HTTP_E_RUNTIME, "HTTP requests not supported - ext/http was not linked against libcurl."); -#endif - break; - } - - case HTTP_MSG_NONE: - default: - http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is neither of type HTTP_MSG_REQUEST nor HTTP_MSG_RESPONSE"); - break; - } - - return rs; -} - -PHP_HTTP_API http_message *_http_message_dup(http_message *orig TSRMLS_DC) -{ - http_message *temp, *copy = NULL; - http_info info; - - if (orig) { - info.type = orig->type; - info.http = orig->http; - - copy = temp = http_message_new(); - http_message_set_info(temp, &info); - zend_hash_copy(&temp->hdrs, &orig->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - phpstr_append(&temp->body, orig->body.data, orig->body.used); - - while (orig->parent) { - info.type = orig->parent->type; - info.http = orig->parent->http; - - temp->parent = http_message_new(); - http_message_set_info(temp->parent, &info); - zend_hash_copy(&temp->parent->hdrs, &orig->parent->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - phpstr_append(&temp->parent->body, orig->parent->body.data, orig->parent->body.used); - - temp = temp->parent; - orig = orig->parent; - } - } - - return copy; -} - -PHP_HTTP_API void _http_message_dtor(http_message *message) -{ - if (message) { - zend_hash_destroy(&message->hdrs); - phpstr_dtor(PHPSTR(message)); - - switch (message->type) { - case HTTP_MSG_REQUEST: - STR_SET(message->http.info.request.method, NULL); - STR_SET(message->http.info.request.url, NULL); - break; - - case HTTP_MSG_RESPONSE: - STR_SET(message->http.info.response.status, NULL); - break; - - default: - break; - } - } -} - -PHP_HTTP_API void _http_message_free(http_message **message) -{ - if (*message) { - if ((*message)->parent) { - http_message_free(&(*message)->parent); - } - http_message_dtor(*message); - efree(*message); - *message = NULL; - } -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_message_object.c b/http_message_object.c deleted file mode 100644 index 0856aef..0000000 --- a/http_message_object.c +++ /dev/null @@ -1,1555 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#define HTTP_WANT_CURL -#define HTTP_WANT_MAGIC -#include "php_http.h" - -#ifdef ZEND_ENGINE_2 - -#include "zend_interfaces.h" -#include "ext/standard/url.h" -#include "php_variables.h" - -#include "php_http_api.h" -#include "php_http_send_api.h" -#include "php_http_url_api.h" -#include "php_http_message_api.h" -#include "php_http_message_object.h" -#include "php_http_exception_object.h" -#include "php_http_response_object.h" -#include "php_http_request_method_api.h" -#include "php_http_request_api.h" -#include "php_http_request_object.h" -#include "php_http_headers_api.h" - -#if defined(HTTP_HAVE_SPL) && !defined(WONKY) -/* SPL doesn't install its headers */ -extern PHPAPI zend_class_entry *spl_ce_Countable; -#endif - -#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpMessage, method, 0, req_args) -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpMessage, method, 0) -#define HTTP_MESSAGE_ME(method, visibility) PHP_ME(HttpMessage, method, HTTP_ARGS(HttpMessage, method), visibility) - -HTTP_BEGIN_ARGS(__construct, 0) - HTTP_ARG_VAL(message, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(factory, 0) - HTTP_ARG_VAL(message, 0) - HTTP_ARG_VAL(class_name, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(fromEnv, 1) - HTTP_ARG_VAL(type, 0) - HTTP_ARG_VAL(class_name, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getBody); -HTTP_BEGIN_ARGS(setBody, 1) - HTTP_ARG_VAL(body, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(getHeader, 1) - HTTP_ARG_VAL(header, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getHeaders); -HTTP_BEGIN_ARGS(setHeaders, 1) - HTTP_ARG_VAL(headers, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(addHeaders, 1) - HTTP_ARG_VAL(headers, 0) - HTTP_ARG_VAL(append, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getType); -HTTP_BEGIN_ARGS(setType, 1) - HTTP_ARG_VAL(type, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getInfo); -HTTP_BEGIN_ARGS(setInfo, 1) - HTTP_ARG_VAL(http_info, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getResponseCode); -HTTP_BEGIN_ARGS(setResponseCode, 1) - HTTP_ARG_VAL(response_code, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getResponseStatus); -HTTP_BEGIN_ARGS(setResponseStatus, 1) - HTTP_ARG_VAL(response_status, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getRequestMethod); -HTTP_BEGIN_ARGS(setRequestMethod, 1) - HTTP_ARG_VAL(request_method, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getRequestUrl); -HTTP_BEGIN_ARGS(setRequestUrl, 1) - HTTP_ARG_VAL(url, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getHttpVersion); -HTTP_BEGIN_ARGS(setHttpVersion, 1) - HTTP_ARG_VAL(http_version, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(guessContentType, 1) - HTTP_ARG_VAL(magic_file, 0) - HTTP_ARG_VAL(magic_mode, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getParentMessage); -HTTP_EMPTY_ARGS(send); -HTTP_EMPTY_ARGS(__toString); -HTTP_BEGIN_ARGS(toString, 0) - HTTP_ARG_VAL(include_parent, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(toMessageTypeObject); - -HTTP_EMPTY_ARGS(count); - -HTTP_EMPTY_ARGS(serialize); -HTTP_BEGIN_ARGS(unserialize, 1) - HTTP_ARG_VAL(serialized, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(rewind); -HTTP_EMPTY_ARGS(valid); -HTTP_EMPTY_ARGS(key); -HTTP_EMPTY_ARGS(current); -HTTP_EMPTY_ARGS(next); - -HTTP_EMPTY_ARGS(detach); -HTTP_BEGIN_ARGS(prepend, 1) - HTTP_ARG_OBJ(HttpMessage, message, 0) -HTTP_END_ARGS; -HTTP_EMPTY_ARGS(reverse); - -#define http_message_object_read_prop _http_message_object_read_prop -static zval *_http_message_object_read_prop(zval *object, zval *member, int type ZEND_LITERAL_KEY_DC TSRMLS_DC); -#define http_message_object_write_prop _http_message_object_write_prop -static void _http_message_object_write_prop(zval *object, zval *member, zval *value ZEND_LITERAL_KEY_DC TSRMLS_DC); -#define http_message_object_get_prop_ptr _http_message_object_get_prop_ptr -static zval **_http_message_object_get_prop_ptr(zval *object, zval *member ZEND_GET_PPTR_TYPE_DC ZEND_LITERAL_KEY_DC TSRMLS_DC); -#define http_message_object_get_props _http_message_object_get_props -static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC); - -#define THIS_CE http_message_object_ce -zend_class_entry *http_message_object_ce; -zend_function_entry http_message_object_fe[] = { - HTTP_MESSAGE_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - HTTP_MESSAGE_ME(getBody, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(setBody, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getHeader, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getHeaders, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(setHeaders, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(addHeaders, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getType, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(setType, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getInfo, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(setInfo, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getResponseCode, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(setResponseCode, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getResponseStatus, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(setResponseStatus, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getRequestMethod, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(setRequestMethod, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getRequestUrl, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(setRequestUrl, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getHttpVersion, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(setHttpVersion, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(guessContentType, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(getParentMessage, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(send, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(toString, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(toMessageTypeObject, ZEND_ACC_PUBLIC) - - /* implements Countable */ - HTTP_MESSAGE_ME(count, ZEND_ACC_PUBLIC) - - /* implements Serializable */ - HTTP_MESSAGE_ME(serialize, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(unserialize, ZEND_ACC_PUBLIC) - - /* implements Iterator */ - HTTP_MESSAGE_ME(rewind, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(valid, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(current, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(key, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(next, ZEND_ACC_PUBLIC) - - ZEND_MALIAS(HttpMessage, __toString, toString, HTTP_ARGS(HttpMessage, __toString), ZEND_ACC_PUBLIC) - - HTTP_MESSAGE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - ZEND_MALIAS(HttpMessage, fromString, factory, HTTP_ARGS(HttpMessage, factory), ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - HTTP_MESSAGE_ME(fromEnv, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - - HTTP_MESSAGE_ME(detach, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(prepend, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(reverse, ZEND_ACC_PUBLIC) - - EMPTY_FUNCTION_ENTRY -}; -static zend_object_handlers http_message_object_handlers; - -static HashTable http_message_object_prophandlers; - -typedef void (*http_message_object_prophandler_func)(http_message_object *o, zval *v TSRMLS_DC); - -typedef struct _http_message_object_prophandler { - http_message_object_prophandler_func read; - http_message_object_prophandler_func write; -} http_message_object_prophandler; - -static STATUS http_message_object_add_prophandler(const char *prop_str, size_t prop_len, http_message_object_prophandler_func read, http_message_object_prophandler_func write) { - http_message_object_prophandler h = { read, write }; - return zend_hash_add(&http_message_object_prophandlers, prop_str, prop_len, (void *) &h, sizeof(h), NULL); -} -static STATUS http_message_object_get_prophandler(const char *prop_str, size_t prop_len, http_message_object_prophandler **handler) { - return zend_hash_find(&http_message_object_prophandlers, prop_str, prop_len, (void *) handler); -} -static void http_message_object_prophandler_get_type(http_message_object *obj, zval *return_value TSRMLS_DC) { - RETVAL_LONG(obj->message->type); -} -static void http_message_object_prophandler_set_type(http_message_object *obj, zval *value TSRMLS_DC) { - zval *cpy = http_zsep(IS_LONG, value); - http_message_set_type(obj->message, Z_LVAL_P(cpy)); - zval_ptr_dtor(&cpy); -} -static void http_message_object_prophandler_get_body(http_message_object *obj, zval *return_value TSRMLS_DC) { - phpstr_fix(PHPSTR(obj->message)); - RETVAL_PHPSTR(PHPSTR(obj->message), 0, 1); -} -static void http_message_object_prophandler_set_body(http_message_object *obj, zval *value TSRMLS_DC) { - zval *cpy = http_zsep(IS_STRING, value); - phpstr_dtor(PHPSTR(obj->message)); - phpstr_from_string_ex(PHPSTR(obj->message), Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); - zval_ptr_dtor(&cpy); -} -static void http_message_object_prophandler_get_request_method(http_message_object *obj, zval *return_value TSRMLS_DC) { - if (HTTP_MSG_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) { - RETVAL_STRING(obj->message->http.info.request.method, 1); - } else { - RETVAL_NULL(); - } -} -static void http_message_object_prophandler_set_request_method(http_message_object *obj, zval *value TSRMLS_DC) { - if (HTTP_MSG_TYPE(REQUEST, obj->message)) { - zval *cpy = http_zsep(IS_STRING, value); - STR_SET(obj->message->http.info.request.method, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy))); - zval_ptr_dtor(&cpy); - } -} -static void http_message_object_prophandler_get_request_url(http_message_object *obj, zval *return_value TSRMLS_DC) { - if (HTTP_MSG_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url) { - RETVAL_STRING(obj->message->http.info.request.url, 1); - } else { - RETVAL_NULL(); - } -} -static void http_message_object_prophandler_set_request_url(http_message_object *obj, zval *value TSRMLS_DC) { - if (HTTP_MSG_TYPE(REQUEST, obj->message)) { - zval *cpy = http_zsep(IS_STRING, value); - STR_SET(obj->message->http.info.request.url, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy))); - zval_ptr_dtor(&cpy); - } -} -static void http_message_object_prophandler_get_response_status(http_message_object *obj, zval *return_value TSRMLS_DC) { - if (HTTP_MSG_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) { - RETVAL_STRING(obj->message->http.info.response.status, 1); - } else { - RETVAL_NULL(); - } -} -static void http_message_object_prophandler_set_response_status(http_message_object *obj, zval *value TSRMLS_DC) { - if (HTTP_MSG_TYPE(RESPONSE, obj->message)) { - zval *cpy = http_zsep(IS_STRING, value); - STR_SET(obj->message->http.info.response.status, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy))); - zval_ptr_dtor(&cpy); - } -} -static void http_message_object_prophandler_get_response_code(http_message_object *obj, zval *return_value TSRMLS_DC) { - if (HTTP_MSG_TYPE(RESPONSE, obj->message)) { - RETVAL_LONG(obj->message->http.info.response.code); - } else { - RETVAL_NULL(); - } -} -static void http_message_object_prophandler_set_response_code(http_message_object *obj, zval *value TSRMLS_DC) { - if (HTTP_MSG_TYPE(RESPONSE, obj->message)) { - zval *cpy = http_zsep(IS_LONG, value); - obj->message->http.info.response.code = Z_LVAL_P(cpy); - zval_ptr_dtor(&cpy); - } -} -static void http_message_object_prophandler_get_http_version(http_message_object *obj, zval *return_value TSRMLS_DC) { - RETVAL_DOUBLE(obj->message->http.version); -} -static void http_message_object_prophandler_set_http_version(http_message_object *obj, zval *value TSRMLS_DC) { - zval *cpy = http_zsep(IS_DOUBLE, value); - obj->message->http.version = Z_DVAL_P(cpy); - zval_ptr_dtor(&cpy); -} -static void http_message_object_prophandler_get_headers(http_message_object *obj, zval *return_value TSRMLS_DC) { - array_init(return_value); - zend_hash_copy(Z_ARRVAL_P(return_value), &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); -} -static void http_message_object_prophandler_set_headers(http_message_object *obj, zval *value TSRMLS_DC) { - zval *cpy = http_zsep(IS_ARRAY, value); - zend_hash_clean(&obj->message->hdrs); - zend_hash_copy(&obj->message->hdrs, Z_ARRVAL_P(cpy), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - zval_ptr_dtor(&cpy); -} -static void http_message_object_prophandler_get_parent_message(http_message_object *obj, zval *return_value TSRMLS_DC) { - if (obj->message->parent) { - RETVAL_OBJVAL(obj->parent, 1); - } else { - RETVAL_NULL(); - } -} -static void http_message_object_prophandler_set_parent_message(http_message_object *obj, zval *value TSRMLS_DC) { - if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), http_message_object_ce TSRMLS_CC)) { - if (obj->message->parent) { - zval tmp; - tmp.value.obj = obj->parent; - Z_OBJ_DELREF(tmp); - } - Z_OBJ_ADDREF_P(value); - obj->parent = value->value.obj; - } -} - -PHP_MINIT_FUNCTION(http_message_object) -{ - HTTP_REGISTER_CLASS_EX(HttpMessage, http_message_object, NULL, 0); - -#ifndef WONKY -# ifdef HTTP_HAVE_SPL - zend_class_implements(http_message_object_ce TSRMLS_CC, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator); -# else - zend_class_implements(http_message_object_ce TSRMLS_CC, 2, zend_ce_serializable, zend_ce_iterator); -# endif -#else - zend_class_implements(http_message_object_ce TSRMLS_CC, 1, zend_ce_iterator); -#endif - - http_message_object_handlers.clone_obj = _http_message_object_clone_obj; - http_message_object_handlers.read_property = http_message_object_read_prop; - http_message_object_handlers.write_property = http_message_object_write_prop; - http_message_object_handlers.get_properties = http_message_object_get_props; - http_message_object_handlers.get_property_ptr_ptr = http_message_object_get_prop_ptr; - - zend_hash_init(&http_message_object_prophandlers, 9, NULL, NULL, 1); - zend_declare_property_long(THIS_CE, ZEND_STRS("type")-1, HTTP_MSG_NONE, ZEND_ACC_PROTECTED TSRMLS_CC); - http_message_object_add_prophandler(ZEND_STRS("type")-1, http_message_object_prophandler_get_type, http_message_object_prophandler_set_type); - zend_declare_property_string(THIS_CE, ZEND_STRS("body")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC); - http_message_object_add_prophandler(ZEND_STRS("body")-1, http_message_object_prophandler_get_body, http_message_object_prophandler_set_body); - zend_declare_property_string(THIS_CE, ZEND_STRS("requestMethod")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC); - http_message_object_add_prophandler(ZEND_STRS("requestMethod")-1, http_message_object_prophandler_get_request_method, http_message_object_prophandler_set_request_method); - zend_declare_property_string(THIS_CE, ZEND_STRS("requestUrl")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC); - http_message_object_add_prophandler(ZEND_STRS("requestUrl")-1, http_message_object_prophandler_get_request_url, http_message_object_prophandler_set_request_url); - zend_declare_property_string(THIS_CE, ZEND_STRS("responseStatus")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC); - http_message_object_add_prophandler(ZEND_STRS("responseStatus")-1, http_message_object_prophandler_get_response_status, http_message_object_prophandler_set_response_status); - zend_declare_property_long(THIS_CE, ZEND_STRS("responseCode")-1, 0, ZEND_ACC_PROTECTED TSRMLS_CC); - http_message_object_add_prophandler(ZEND_STRS("responseCode")-1, http_message_object_prophandler_get_response_code, http_message_object_prophandler_set_response_code); - zend_declare_property_null(THIS_CE, ZEND_STRS("httpVersion")-1, ZEND_ACC_PROTECTED TSRMLS_CC); - http_message_object_add_prophandler(ZEND_STRS("httpVersion")-1, http_message_object_prophandler_get_http_version, http_message_object_prophandler_set_http_version); - zend_declare_property_null(THIS_CE, ZEND_STRS("headers")-1, ZEND_ACC_PROTECTED TSRMLS_CC); - http_message_object_add_prophandler(ZEND_STRS("headers")-1, http_message_object_prophandler_get_headers, http_message_object_prophandler_set_headers); - zend_declare_property_null(THIS_CE, ZEND_STRS("parentMessage")-1, ZEND_ACC_PROTECTED TSRMLS_CC); - http_message_object_add_prophandler(ZEND_STRS("parentMessage")-1, http_message_object_prophandler_get_parent_message, http_message_object_prophandler_set_parent_message); - -#ifndef WONKY - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_NONE")-1, HTTP_MSG_NONE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_REQUEST")-1, HTTP_MSG_REQUEST TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_RESPONSE")-1, HTTP_MSG_RESPONSE TSRMLS_CC); -#endif - - HTTP_LONG_CONSTANT("HTTP_MSG_NONE", HTTP_MSG_NONE); - HTTP_LONG_CONSTANT("HTTP_MSG_REQUEST", HTTP_MSG_REQUEST); - HTTP_LONG_CONSTANT("HTTP_MSG_RESPONSE", HTTP_MSG_RESPONSE); - - return SUCCESS; -} - -PHP_MSHUTDOWN_FUNCTION(http_message_object) -{ - zend_hash_destroy(&http_message_object_prophandlers); - - return SUCCESS; -} - -void _http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC) -{ - int i; - getObject(http_message_object, obj); - - /* count */ - http_message_count(i, obj->message); - - if (i > 1) { - zval o; - zend_object_value *ovalues = NULL; - http_message_object **objects = NULL; - int last = i - 1; - - objects = ecalloc(i, sizeof(http_message_object *)); - ovalues = ecalloc(i, sizeof(zend_object_value)); - - /* we are the first message */ - objects[0] = obj; - ovalues[0] = getThis()->value.obj; - - /* fetch parents */ - INIT_PZVAL(&o); - o.type = IS_OBJECT; - for (i = 1; obj->parent.handle; ++i) { - o.value.obj = obj->parent; - ovalues[i] = o.value.obj; - objects[i] = obj = zend_object_store_get_object(&o TSRMLS_CC); - } - - /* reorder parents */ - for (last = --i; i; --i) { - objects[i]->message->parent = objects[i-1]->message; - objects[i]->parent = ovalues[i-1]; - } - objects[0]->message->parent = NULL; - objects[0]->parent.handle = 0; - objects[0]->parent.handlers = NULL; - - /* add ref (why?) */ - Z_OBJ_ADDREF_P(getThis()); - RETVAL_OBJVAL(ovalues[last], 1); - - efree(objects); - efree(ovalues); - } else { - RETURN_ZVAL(getThis(), 1, 0); - } -} - -void _http_message_object_prepend_ex(zval *this_ptr, zval *prepend, zend_bool top TSRMLS_DC) -{ - zval m; - http_message *save_parent_msg = NULL; - zend_object_value save_parent_obj = {0, NULL}; - getObject(http_message_object, obj); - getObjectEx(http_message_object, prepend_obj, prepend); - - INIT_PZVAL(&m); - m.type = IS_OBJECT; - - if (!top) { - save_parent_obj = obj->parent; - save_parent_msg = obj->message->parent; - } else { - /* iterate to the most parent object */ - while (obj->parent.handle) { - m.value.obj = obj->parent; - obj = zend_object_store_get_object(&m TSRMLS_CC); - } - } - - /* prepend */ - obj->parent = prepend->value.obj; - obj->message->parent = prepend_obj->message; - - /* add ref */ - zend_objects_store_add_ref(prepend TSRMLS_CC); - while (prepend_obj->parent.handle) { - m.value.obj = prepend_obj->parent; - zend_objects_store_add_ref(&m TSRMLS_CC); - prepend_obj = zend_object_store_get_object(&m TSRMLS_CC); - } - - if (!top) { - prepend_obj->parent = save_parent_obj; - prepend_obj->message->parent = save_parent_msg; - } -} - -zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return http_message_object_new_ex(ce, NULL, NULL); -} - -zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg, http_message_object **ptr TSRMLS_DC) -{ - zend_object_value ov; - http_message_object *o; - - o = ecalloc(1, sizeof(http_message_object)); - o->zo.ce = ce; - - if (ptr) { - *ptr = o; - } - - if (msg) { - o->message = msg; - if (msg->parent) { - o->parent = http_message_object_new_ex(ce, msg->parent, NULL); - } - } - - -#ifdef ZEND_ENGINE_2_4 - zend_object_std_init(o, ce TSRMLS_CC); - object_properties_init(o, ce); -#else - ALLOC_HASHTABLE(OBJ_PROP(o)); - zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); -#endif - - ov.handle = putObject(http_message_object, o); - ov.handlers = &http_message_object_handlers; - - return ov; -} - -zend_object_value _http_message_object_clone_obj(zval *this_ptr TSRMLS_DC) -{ - zend_object_value new_ov; - http_message_object *new_obj = NULL; - getObject(http_message_object, old_obj); - - new_ov = http_message_object_new_ex(old_obj->zo.ce, http_message_dup(old_obj->message), &new_obj); - zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); - - return new_ov; -} - -void _http_message_object_free(zend_object *object TSRMLS_DC) -{ - http_message_object *o = (http_message_object *) object; - - if (o->iterator) { - zval_ptr_dtor(&o->iterator); - o->iterator = NULL; - } - if (o->message) { - http_message_dtor(o->message); - efree(o->message); - } - if (o->parent.handle) { - zval p; - - INIT_PZVAL(&p); - p.type = IS_OBJECT; - p.value.obj = o->parent; - zend_objects_store_del_ref(&p TSRMLS_CC); - } - freeObject(o); -} - -static zval **_http_message_object_get_prop_ptr(zval *object, zval *member ZEND_GET_PPTR_TYPE_DC ZEND_LITERAL_KEY_DC TSRMLS_DC) { - getObjectEx(http_message_object, obj, object); - http_message_object_prophandler *handler; - - if (SUCCESS == http_message_object_get_prophandler(Z_STRVAL_P(member), Z_STRLEN_P(member), &handler)) { - zend_error(E_ERROR, "Cannot access HttpMessage properties by reference or array key/index"); - return NULL; - } - - return zend_get_std_object_handlers()->get_property_ptr_ptr(object, member ZEND_GET_PPTR_TYPE_CC ZEND_LITERAL_KEY_CC TSRMLS_CC); -} - -static zval *_http_message_object_read_prop(zval *object, zval *member, int type ZEND_LITERAL_KEY_DC TSRMLS_DC) -{ - getObjectEx(http_message_object, obj, object); - http_message_object_prophandler *handler; - zval *return_value; - - if (SUCCESS == http_message_object_get_prophandler(Z_STRVAL_P(member), Z_STRLEN_P(member), &handler)) { - if (type == BP_VAR_W) { - zend_error(E_ERROR, "Cannot access HttpMessage properties by reference or array key/index"); - return NULL; - } - - ALLOC_ZVAL(return_value); -#ifdef Z_SET_REFCOUNT - Z_SET_REFCOUNT_P(return_value, 0); - Z_UNSET_ISREF_P(return_value); -#else - return_value->refcount = 0; - return_value->is_ref = 0; -#endif - - handler->read(obj, return_value TSRMLS_CC); - - } else { - return_value = zend_get_std_object_handlers()->read_property(object, member, type ZEND_LITERAL_KEY_CC TSRMLS_CC); - } - - return return_value; -} - -static void _http_message_object_write_prop(zval *object, zval *member, zval *value ZEND_LITERAL_KEY_DC TSRMLS_DC) -{ - getObjectEx(http_message_object, obj, object); - http_message_object_prophandler *handler; - - if (SUCCESS == http_message_object_get_prophandler(Z_STRVAL_P(member), Z_STRLEN_P(member), &handler)) { - handler->write(obj, value TSRMLS_CC); - } else { - zend_get_std_object_handlers()->write_property(object, member, value ZEND_LITERAL_KEY_CC TSRMLS_CC); - } -} - -static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC) -{ - zval *headers; - getObjectEx(http_message_object, obj, object); - http_message *msg = obj->message; - zval array, *parent; -#ifdef ZEND_ENGINE_2_4 - HashTable *props = zend_get_std_object_handlers()->get_properties(object TSRMLS_CC); -#else - HashTable *props = OBJ_PROP(obj); -#endif - INIT_ZARR(array, props); - -#define ASSOC_PROP(array, ptype, name, val) \ - { \ - char *m_prop_name; \ - int m_prop_len; \ - zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \ - add_assoc_ ##ptype## _ex(&array, m_prop_name, sizeof(name)+3, val); \ - efree(m_prop_name); \ - } -#define ASSOC_STRING(array, name, val) ASSOC_STRINGL(array, name, val, strlen(val)) -#define ASSOC_STRINGL(array, name, val, len) \ - { \ - char *m_prop_name; \ - int m_prop_len; \ - zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 0); \ - add_assoc_stringl_ex(&array, m_prop_name, sizeof(name)+3, val, len, 1); \ - efree(m_prop_name); \ - } - - ASSOC_PROP(array, long, "type", msg->type); - ASSOC_PROP(array, double, "httpVersion", msg->http.version); - - switch (msg->type) { - case HTTP_MSG_REQUEST: - ASSOC_PROP(array, long, "responseCode", 0); - ASSOC_STRINGL(array, "responseStatus", "", 0); - ASSOC_STRING(array, "requestMethod", STR_PTR(msg->http.info.request.method)); - ASSOC_STRING(array, "requestUrl", STR_PTR(msg->http.info.request.url)); - break; - - case HTTP_MSG_RESPONSE: - ASSOC_PROP(array, long, "responseCode", msg->http.info.response.code); - ASSOC_STRING(array, "responseStatus", STR_PTR(msg->http.info.response.status)); - ASSOC_STRINGL(array, "requestMethod", "", 0); - ASSOC_STRINGL(array, "requestUrl", "", 0); - break; - - case HTTP_MSG_NONE: - default: - ASSOC_PROP(array, long, "responseCode", 0); - ASSOC_STRINGL(array, "responseStatus", "", 0); - ASSOC_STRINGL(array, "requestMethod", "", 0); - ASSOC_STRINGL(array, "requestUrl", "", 0); - break; - } - - MAKE_STD_ZVAL(headers); - array_init(headers); - zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - ASSOC_PROP(array, zval, "headers", headers); - ASSOC_STRINGL(array, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg)); - - MAKE_STD_ZVAL(parent); - if (msg->parent) { - ZVAL_OBJVAL(parent, obj->parent, 1); - } else { - ZVAL_NULL(parent); - } - ASSOC_PROP(array, zval, "parentMessage", parent); - - return props; -} - -/* ### USERLAND ### */ - -/* {{{ proto void HttpMessage::__construct([string message]) - Create a new HttpMessage object instance. */ -PHP_METHOD(HttpMessage, __construct) -{ - int length = 0; - char *message = NULL; - - getObject(http_message_object, obj); - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) { - http_message *msg = obj->message; - - http_message_dtor(msg); - if ((obj->message = http_message_parse_ex(msg, message, length))) { - if (obj->message->parent) { - obj->parent = http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, NULL); - } - } else { - obj->message = http_message_init(msg); - } - } - if (!obj->message) { - obj->message = http_message_new(); - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto static HttpMessage HttpMessage::factory([string raw_message[, string class_name = "HttpMessage"]]) - Create a new HttpMessage object instance. */ -PHP_METHOD(HttpMessage, factory) -{ - char *string = NULL, *cn = NULL; - int length = 0, cl = 0; - http_message *msg = NULL; - zend_object_value ov; - http_message_object *obj = NULL; - - RETVAL_NULL(); - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &string, &length, &cn, &cl)) { - if (length) { - msg = http_message_parse(string, length); - } - if ((msg || !length) && SUCCESS == http_object_new(&ov, cn, cl, _http_message_object_new_ex, http_message_object_ce, msg, &obj)) { - RETVAL_OBJVAL(ov, 0); - } - if (obj && !obj->message) { - obj->message = http_message_new(); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto static HttpMessage HttpMessage::fromEnv(int type[, string class_name = "HttpMessage"]) - Create a new HttpMessage object from environment representing either current request or response */ -PHP_METHOD(HttpMessage, fromEnv) -{ - char *cn = NULL; - int cl = 0; - long type; - http_message_object *obj = NULL; - zend_object_value ov; - - RETVAL_NULL(); - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &type, &cn, &cl)) { - if (SUCCESS == http_object_new(&ov, cn, cl, _http_message_object_new_ex, http_message_object_ce, http_message_init_env(NULL, type), &obj)) { - RETVAL_OBJVAL(ov, 0); - } - if (obj && !obj->message) { - obj->message = http_message_new(); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto string HttpMessage::getBody() - Get the body of the parsed HttpMessage. */ -PHP_METHOD(HttpMessage, getBody) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_message_object, obj); - RETURN_PHPSTR(&obj->message->body, PHPSTR_FREE_NOT, 1); - } -} -/* }}} */ - -/* {{{ proto void HttpMessage::setBody(string body) - Set the body of the HttpMessage. NOTE: Don't forget to update any headers accordingly. */ -PHP_METHOD(HttpMessage, setBody) -{ - char *body; - int len; - getObject(http_message_object, obj); - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &body, &len)) { - phpstr_dtor(PHPSTR(obj->message)); - phpstr_from_string_ex(PHPSTR(obj->message), body, len); - } -} -/* }}} */ - -/* {{{ proto string HttpMessage::getHeader(string header) - Get message header. */ -PHP_METHOD(HttpMessage, getHeader) -{ - zval *header; - char *orig_header, *nice_header; - int header_len; - getObject(http_message_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &orig_header, &header_len)) { - RETURN_FALSE; - } - - nice_header = pretty_key(estrndup(orig_header, header_len), header_len, 1, 1); - if ((header = http_message_header_ex(obj->message, nice_header, header_len + 1, 0))) { - RETVAL_ZVAL(header, 1, 1); - } - efree(nice_header); -} -/* }}} */ - -/* {{{ proto array HttpMessage::getHeaders() - Get Message Headers. */ -PHP_METHOD(HttpMessage, getHeaders) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_message_object, obj); - - array_init(return_value); - array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value)); - } -} -/* }}} */ - -/* {{{ proto void HttpMessage::setHeaders(array headers) - Sets new headers. */ -PHP_METHOD(HttpMessage, setHeaders) -{ - zval *new_headers = NULL; - getObject(http_message_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &new_headers)) { - return; - } - - zend_hash_clean(&obj->message->hdrs); - if (new_headers) { - array_copy(Z_ARRVAL_P(new_headers), &obj->message->hdrs); - } -} -/* }}} */ - -/* {{{ proto void HttpMessage::addHeaders(array headers[, bool append = false]) - Add headers. If append is true, headers with the same name will be separated, else overwritten. */ -PHP_METHOD(HttpMessage, addHeaders) -{ - zval *new_headers; - zend_bool append = 0; - getObject(http_message_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) { - return; - } - - array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY); -} -/* }}} */ - -/* {{{ proto int HttpMessage::getType() - Get Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE) */ -PHP_METHOD(HttpMessage, getType) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_message_object, obj); - RETURN_LONG(obj->message->type); - } -} -/* }}} */ - -/* {{{ proto void HttpMessage::setType(int type) - Set Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE) */ -PHP_METHOD(HttpMessage, setType) -{ - long type; - getObject(http_message_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) { - return; - } - http_message_set_type(obj->message, type); -} -/* }}} */ - -/* {{{ proto string HttpMessage::getInfo(void) - Get the HTTP request/response line */ -PHP_METHOD(HttpMessage, getInfo) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_message_object, obj); - - switch (obj->message->type) { - case HTTP_MSG_REQUEST: - Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, "")); - break; - case HTTP_MSG_RESPONSE: - Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, "")); - break; - default: - RETURN_NULL(); - break; - } - Z_TYPE_P(return_value) = IS_STRING; - } -} -/* }}} */ - -/* {{{ proto bool HttpMessage::setInfo(string http_info) - Set type and request or response info with a standard HTTP request or response line */ -PHP_METHOD(HttpMessage, setInfo) -{ - char *str; - int len; - http_info inf; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) && SUCCESS == http_info_parse_ex(str, &inf, 0)) { - getObject(http_message_object, obj); - - http_message_set_info(obj->message, &inf); - http_info_dtor(&inf); - RETURN_TRUE; - } - RETURN_FALSE; -} -/* }}} */ - -/* {{{ proto int HttpMessage::getResponseCode() - Get the Response Code of the Message. */ -PHP_METHOD(HttpMessage, getResponseCode) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_message_object, obj); - HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE); - RETURN_LONG(obj->message->http.info.response.code); - } -} -/* }}} */ - -/* {{{ proto bool HttpMessage::setResponseCode(int code) - Set the response code of an HTTP Response Message. */ -PHP_METHOD(HttpMessage, setResponseCode) -{ - long code; - getObject(http_message_object, obj); - - HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) { - RETURN_FALSE; - } - if (code < 100 || code > 599) { - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid response code (100-599): %ld", code); - RETURN_FALSE; - } - - obj->message->http.info.response.code = code; - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpMessage::getResponseStatus() - Get the Response Status of the message (i.e. the string following the response code). */ -PHP_METHOD(HttpMessage, getResponseStatus) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_message_object, obj); - HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE); - if (obj->message->http.info.response.status) { - RETURN_STRING(obj->message->http.info.response.status, 1); - } else { - RETURN_EMPTY_STRING(); - } - } -} -/* }}} */ - -/* {{{ proto bool HttpMessage::setResponseStatus(string status) - Set the Response Status of the HTTP message (i.e. the string following the response code). */ -PHP_METHOD(HttpMessage, setResponseStatus) -{ - char *status; - int status_len; - getObject(http_message_object, obj); - - HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &status, &status_len)) { - RETURN_FALSE; - } - STR_SET(obj->message->http.info.response.status, estrndup(status, status_len)); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpMessage::getRequestMethod() - Get the Request Method of the Message. */ -PHP_METHOD(HttpMessage, getRequestMethod) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_message_object, obj); - HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE); - if (obj->message->http.info.request.method) { - RETURN_STRING(obj->message->http.info.request.method, 1); - } else { - RETURN_EMPTY_STRING(); - } - } -} -/* }}} */ - -/* {{{ proto bool HttpMessage::setRequestMethod(string method) - Set the Request Method of the HTTP Message. */ -PHP_METHOD(HttpMessage, setRequestMethod) -{ - char *method; - int method_len; - getObject(http_message_object, obj); - - HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) { - RETURN_FALSE; - } - if (method_len < 1) { - http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestMethod to an empty string"); - RETURN_FALSE; - } - if (!http_request_method_exists(1, 0, method)) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Unknown request method: %s", method); - RETURN_FALSE; - } - - STR_SET(obj->message->http.info.request.method, estrndup(method, method_len)); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpMessage::getRequestUrl() - Get the Request URL of the Message. */ -PHP_METHOD(HttpMessage, getRequestUrl) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_message_object, obj); - HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE); - if (obj->message->http.info.request.url) { - RETURN_STRING(obj->message->http.info.request.url, 1); - } else { - RETURN_EMPTY_STRING(); - } - } -} -/* }}} */ - -/* {{{ proto bool HttpMessage::setRequestUrl(string url) - Set the Request URL of the HTTP Message. */ -PHP_METHOD(HttpMessage, setRequestUrl) -{ - char *URI; - int URIlen; - getObject(http_message_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URI, &URIlen)) { - RETURN_FALSE; - } - HTTP_CHECK_MESSAGE_TYPE_REQUEST(obj->message, RETURN_FALSE); - if (URIlen < 1) { - http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestUrl to an empty string"); - RETURN_FALSE; - } - - STR_SET(obj->message->http.info.request.url, estrndup(URI, URIlen)); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpMessage::getHttpVersion() - Get the HTTP Protocol Version of the Message. */ -PHP_METHOD(HttpMessage, getHttpVersion) -{ - NO_ARGS; - - if (return_value_used) { - char *version; - getObject(http_message_object, obj); - - spprintf(&version, 0, "%1.1F", obj->message->http.version); - RETURN_STRING(version, 0); - } -} -/* }}} */ - -/* {{{ proto bool HttpMessage::setHttpVersion(string version) - Set the HTTP Protocol version of the Message. */ -PHP_METHOD(HttpMessage, setHttpVersion) -{ - zval *zv; - char *version; - getObject(http_message_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &zv)) { - return; - } - - convert_to_double(zv); - spprintf(&version, 0, "%1.1F", Z_DVAL_P(zv)); - if (strcmp(version, "1.0") && strcmp(version, "1.1")) { - efree(version); - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid HTTP protocol version (1.0 or 1.1): %g", Z_DVAL_P(zv)); - RETURN_FALSE; - } - efree(version); - obj->message->http.version = Z_DVAL_P(zv); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpMessage::guessContentType(string magic_file[, int magic_mode = MAGIC_MIME]) - Attempts to guess the content type of supplied payload through libmagic. */ -PHP_METHOD(HttpMessage, guessContentType) -{ -#ifdef HTTP_HAVE_MAGIC - char *magic_file, *ct = NULL; - int magic_file_len; - long magic_mode = MAGIC_MIME; - - RETVAL_FALSE; - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &magic_file, &magic_file_len, &magic_mode)) { - getObject(http_message_object, obj); - if ((ct = http_guess_content_type(magic_file, magic_mode, PHPSTR_VAL(&obj->message->body), PHPSTR_LEN(&obj->message->body), SEND_DATA))) { - RETVAL_STRING(ct, 0); - } - } - SET_EH_NORMAL(); -#else - http_error(HE_THROW, HTTP_E_RUNTIME, "Cannot guess Content-Type; libmagic not available"); - RETURN_FALSE; -#endif -} -/* }}} */ - -/* {{{ proto HttpMessage HttpMessage::getParentMessage() - Get parent Message. */ -PHP_METHOD(HttpMessage, getParentMessage) -{ - SET_EH_THROW_HTTP(); - NO_ARGS { - getObject(http_message_object, obj); - - if (obj->message->parent) { - RETVAL_OBJVAL(obj->parent, 1); - } else { - http_error(HE_WARNING, HTTP_E_RUNTIME, "HttpMessage does not have a parent message"); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto bool HttpMessage::send() - Send the Message according to its type as Response or Request. */ -PHP_METHOD(HttpMessage, send) -{ - getObject(http_message_object, obj); - - NO_ARGS; - - RETURN_SUCCESS(http_message_send(obj->message)); -} -/* }}} */ - -/* {{{ proto string HttpMessage::toString([bool include_parent = false]) - Get the string representation of the Message. */ -PHP_METHOD(HttpMessage, toString) -{ - if (return_value_used) { - char *string; - size_t length; - zend_bool include_parent = 0; - getObject(http_message_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) { - RETURN_FALSE; - } - - if (include_parent) { - http_message_serialize(obj->message, &string, &length); - } else { - http_message_tostring(obj->message, &string, &length); - } - RETURN_STRINGL(string, length, 0); - } -} -/* }}} */ - -/* {{{ proto HttpRequest|HttpResponse HttpMessage::toMessageTypeObject(void) - Creates an object regarding to the type of the message. Returns either an HttpRequest or HttpResponse object on success, or NULL on failure. */ -PHP_METHOD(HttpMessage, toMessageTypeObject) -{ - SET_EH_THROW_HTTP(); - - NO_ARGS; - - if (return_value_used) { - getObject(http_message_object, obj); - - switch (obj->message->type) { - case HTTP_MSG_REQUEST: - { -#ifdef HTTP_HAVE_CURL - int method; - char *url; - zval post, body, *array, *headers, *host = http_message_header(obj->message, "Host"); - php_url hurl, *purl = php_url_parse(STR_PTR(obj->message->http.info.request.url)); - - MAKE_STD_ZVAL(array); - array_init(array); - - memset(&hurl, 0, sizeof(php_url)); - if (host) { - hurl.host = Z_STRVAL_P(host); - zval_ptr_dtor(&host); - } - http_build_url(HTTP_URL_REPLACE, purl, &hurl, NULL, &url, NULL); - php_url_free(purl); - add_assoc_string(array, "url", url, 0); - - if ( obj->message->http.info.request.method && - ((method = http_request_method_exists(1, 0, obj->message->http.info.request.method)) || - (method = http_request_method_register(obj->message->http.info.request.method, strlen(obj->message->http.info.request.method))))) { - add_assoc_long(array, "method", method); - } - - if (10 == (int) (obj->message->http.version * 10)) { - add_assoc_long(array, "protocol", CURL_HTTP_VERSION_1_0); - } - - MAKE_STD_ZVAL(headers); - array_init(headers); - array_copy(&obj->message->hdrs, Z_ARRVAL_P(headers)); - add_assoc_zval(array, "headers", headers); - - object_init_ex(return_value, http_request_object_ce); - zend_call_method_with_1_params(&return_value, http_request_object_ce, NULL, "setoptions", NULL, array); - zval_ptr_dtor(&array); - - if (PHPSTR_VAL(obj->message) && PHPSTR_LEN(obj->message)) { - phpstr_fix(PHPSTR(obj->message)); - INIT_PZVAL(&body); - ZVAL_STRINGL(&body, PHPSTR_VAL(obj->message), PHPSTR_LEN(obj->message), 0); - if (method != HTTP_POST) { - zend_call_method_with_1_params(&return_value, http_request_object_ce, NULL, "setbody", NULL, &body); - } else { - INIT_PZVAL(&post); - array_init(&post); - - zval_copy_ctor(&body); - sapi_module.treat_data(PARSE_STRING, Z_STRVAL(body), &post TSRMLS_CC); - zend_call_method_with_1_params(&return_value, http_request_object_ce, NULL, "setpostfields", NULL, &post); - zval_dtor(&post); - } - } -#else - http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot transform HttpMessage to HttpRequest (missing curl support)"); -#endif - break; - } - - case HTTP_MSG_RESPONSE: - { -#ifndef WONKY - HashPosition pos1, pos2; - HashKey key = initHashKey(0); - zval **header, **h, *body; - - if (obj->message->http.info.response.code) { - http_send_status(obj->message->http.info.response.code); - } - - object_init_ex(return_value, http_response_object_ce); - - FOREACH_HASH_KEYVAL(pos1, &obj->message->hdrs, key, header) { - if (key.type == HASH_KEY_IS_STRING) { - zval *zkey; - - MAKE_STD_ZVAL(zkey); - ZVAL_STRINGL(zkey, key.str, key.len - 1, 1); - - switch (Z_TYPE_PP(header)) { - case IS_ARRAY: - case IS_OBJECT: - FOREACH_HASH_VAL(pos2, HASH_OF(*header), h) { - ZVAL_ADDREF(*h); - zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, zkey, *h); - zval_ptr_dtor(h); - } - break; - - default: - ZVAL_ADDREF(*header); - zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, zkey, *header); - zval_ptr_dtor(header); - break; - } - zval_ptr_dtor(&zkey); - } - } - - MAKE_STD_ZVAL(body); - ZVAL_STRINGL(body, PHPSTR_VAL(obj->message), PHPSTR_LEN(obj->message), 1); - zend_call_method_with_1_params(&return_value, http_response_object_ce, NULL, "setdata", NULL, body); - zval_ptr_dtor(&body); -#else - http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot transform HttpMessage to HttpResponse (need PHP 5.1+)"); -#endif - break; - } - - default: - http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "HttpMessage is neither of type HttpMessage::TYPE_REQUEST nor HttpMessage::TYPE_RESPONSE"); - break; - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto int HttpMessage::count() - Implements Countable::count(). Returns the number of parent messages + 1. */ -PHP_METHOD(HttpMessage, count) -{ - NO_ARGS { - long i; - getObject(http_message_object, obj); - - http_message_count(i, obj->message); - RETURN_LONG(i); - } -} -/* }}} */ - -/* {{{ proto string HttpMessage::serialize() - Implements Serializable::serialize(). Returns the serialized representation of the HttpMessage. */ -PHP_METHOD(HttpMessage, serialize) -{ - NO_ARGS { - char *string; - size_t length; - getObject(http_message_object, obj); - - http_message_serialize(obj->message, &string, &length); - RETURN_STRINGL(string, length, 0); - } -} -/* }}} */ - -/* {{{ proto void HttpMessage::unserialize(string serialized) - Implements Serializable::unserialize(). Re-constructs the HttpMessage based upon the serialized string. */ -PHP_METHOD(HttpMessage, unserialize) -{ - int length; - char *serialized; - getObject(http_message_object, obj); - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &serialized, &length)) { - http_message *msg; - - http_message_dtor(obj->message); - if ((msg = http_message_parse_ex(obj->message, serialized, (size_t) length))) { - obj->message = msg; - } else { - http_message_init(obj->message); - http_error(HE_ERROR, HTTP_E_RUNTIME, "Could not unserialize HttpMessage"); - } - } -} -/* }}} */ - -/* {{{ proto HttpMessage HttpMessage::detach(void) - Returns a clone of an HttpMessage object detached from any parent messages. */ -PHP_METHOD(HttpMessage, detach) -{ - http_info info; - http_message *msg; - getObject(http_message_object, obj); - - NO_ARGS; - - info.type = obj->message->type; - memcpy(&HTTP_INFO(&info), &HTTP_INFO(obj->message), sizeof(struct http_info)); - - msg = http_message_new(); - http_message_set_info(msg, &info); - - zend_hash_copy(&msg->hdrs, &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - phpstr_append(&msg->body, PHPSTR_VAL(obj->message), PHPSTR_LEN(obj->message)); - - RETVAL_OBJVAL(http_message_object_new_ex(Z_OBJCE_P(getThis()), msg, NULL), 0); -} -/* }}} */ - -/* {{{ proto void HttpMessage::prepend(HttpMessage message[, bool top = true]) - Prepends message(s) to the HTTP message. Throws HttpInvalidParamException if the message is located within the same message chain. */ -PHP_METHOD(HttpMessage, prepend) -{ - zval *prepend; - zend_bool top = 1; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &prepend, http_message_object_ce, &top)) { - http_message *msg[2]; - getObject(http_message_object, obj); - getObjectEx(http_message_object, prepend_obj, prepend); - - /* safety check */ - for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) { - for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) { - if (msg[0] == msg[1]) { - http_error(HE_THROW, HTTP_E_INVALID_PARAM, "Cannot prepend a message located within the same message chain"); - return; - } - } - } - - http_message_object_prepend_ex(getThis(), prepend, top); - } -} -/* }}} */ - -/* {{{ proto HttpMessage HttpMessage::reverse() - Reorders the message chain in reverse order. Returns the most parent HttpMessage object. */ -PHP_METHOD(HttpMessage, reverse) -{ - NO_ARGS { - http_message_object_reverse(getThis(), return_value); - } -} -/* }}} */ - -/* {{{ proto void HttpMessage::rewind(void) - Implements Iterator::rewind(). */ -PHP_METHOD(HttpMessage, rewind) -{ - NO_ARGS { - getObject(http_message_object, obj); - - if (obj->iterator) { - zval_ptr_dtor(&obj->iterator); - } - ZVAL_ADDREF(getThis()); - obj->iterator = getThis(); - } -} -/* }}} */ - -/* {{{ proto bool HttpMessage::valid(void) - Implements Iterator::valid(). */ -PHP_METHOD(HttpMessage, valid) -{ - NO_ARGS { - getObject(http_message_object, obj); - - RETURN_BOOL(obj->iterator != NULL); - } -} -/* }}} */ - -/* {{{ proto void HttpMessage::next(void) - Implements Iterator::next(). */ -PHP_METHOD(HttpMessage, next) -{ - NO_ARGS { - getObject(http_message_object, obj); - if (obj->iterator) { - getObjectEx(http_message_object, itr, obj->iterator); - - if (itr && itr->parent.handle) { - zval *old = obj->iterator; - MAKE_STD_ZVAL(obj->iterator); - ZVAL_OBJVAL(obj->iterator, itr->parent, 1); - zval_ptr_dtor(&old); - } else { - zval_ptr_dtor(&obj->iterator); - obj->iterator = NULL; - } - } - } -} -/* }}} */ - -/* {{{ proto int HttpMessage::key(void) - Implements Iterator::key(). */ -PHP_METHOD(HttpMessage, key) -{ - NO_ARGS { - getObject(http_message_object, obj); - - RETURN_LONG(obj->iterator ? obj->iterator->value.obj.handle:0); - } -} -/* }}} */ - -/* {{{ proto HttpMessage HttpMessage::current(void) - Implements Iterator::current(). */ -PHP_METHOD(HttpMessage, current) -{ - NO_ARGS { - getObject(http_message_object, obj); - - if (obj->iterator) { - RETURN_ZVAL(obj->iterator, 1, 0); - } - } -} -/* }}} */ - -#endif /* ZEND_ENGINE_2 */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_persistent_handle_api.c b/http_persistent_handle_api.c deleted file mode 100644 index 84f1b48..0000000 --- a/http_persistent_handle_api.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "php_http.h" -#include "php_http_api.h" - -#include "php_http_persistent_handle_api.h" - -#ifndef HTTP_DEBUG_PHANDLES -# define HTTP_DEBUG_PHANDLES 0 -#endif -#if HTTP_DEBUG_PHANDLES -# undef inline -# define inline -#endif - -static HashTable http_persistent_handles_hash; -#ifdef ZTS -# define LOCK() tsrm_mutex_lock(http_persistent_handles_lock) -# define UNLOCK() tsrm_mutex_unlock(http_persistent_handles_lock) -static MUTEX_T http_persistent_handles_lock; -#else -# define LOCK() -# define UNLOCK() -#endif - -typedef struct _http_persistent_handle_list_t { - HashTable free; - ulong used; -} http_persistent_handle_list; - -typedef struct _http_persistent_handle_provider_t { - http_persistent_handle_list list; /* "ident" => array(handles) entries */ - http_persistent_handle_ctor ctor; - http_persistent_handle_dtor dtor; - http_persistent_handle_copy copy; -} http_persistent_handle_provider; - -static inline http_persistent_handle_list *http_persistent_handle_list_init(http_persistent_handle_list *list) -{ - int free_list; - - if ((free_list = !list)) { - list = pemalloc(sizeof(http_persistent_handle_list), 1); - } - - list->used = 0; - - if (SUCCESS != zend_hash_init(&list->free, 0, NULL, NULL, 1)) { - if (free_list) { - pefree(list, 1); - } - list = NULL; - } - - return list; -} - -static inline void http_persistent_handle_list_dtor(http_persistent_handle_list *list, http_persistent_handle_dtor dtor) -{ - HashPosition pos; - void **handle; - -#if HTTP_DEBUG_PHANDLES - fprintf(stderr, "LSTDTOR: %p\n", list); -#endif - FOREACH_HASH_VAL(pos, &list->free, handle) { -#if HTTP_DEBUG_PHANDLES - fprintf(stderr, "DESTROY: %p\n", *handle); -#endif - - dtor(*handle); - } - zend_hash_destroy(&list->free); -} - -static inline void http_persistent_handle_list_free(http_persistent_handle_list **list, http_persistent_handle_dtor dtor) -{ - http_persistent_handle_list_dtor(*list, dtor); -#if HTTP_DEBUG_PHANDLES - fprintf(stderr, "LSTFREE: %p\n", *list); -#endif - pefree(*list, 1); - *list = NULL; -} - -static inline http_persistent_handle_list *http_persistent_handle_list_find(http_persistent_handle_provider *provider TSRMLS_DC) -{ - http_persistent_handle_list **list, *new_list; - - if (SUCCESS == zend_hash_quick_find(&provider->list.free, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &list)) { -#if HTTP_DEBUG_PHANDLES - fprintf(stderr, "LSTFIND: %p\n", *list); -#endif - return *list; - } - - if ((new_list = http_persistent_handle_list_init(NULL))) { - if (SUCCESS == zend_hash_quick_add(&provider->list.free, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &new_list, sizeof(http_persistent_handle_list *), (void *) &list)) { -#if HTTP_DEBUG_PHANDLES - fprintf(stderr, "LSTFIND: %p (new)\n", *list); -#endif - return *list; - } - http_persistent_handle_list_free(&new_list, provider->dtor); - } - - return NULL; -} - -static inline STATUS http_persistent_handle_do_acquire(http_persistent_handle_provider *provider, void **handle TSRMLS_DC) -{ - ulong index; - void **handle_ptr; - http_persistent_handle_list *list; - - if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { - zend_hash_internal_pointer_end(&list->free); - if (HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&list->free, NULL, &index, 0) && SUCCESS == zend_hash_get_current_data(&list->free, (void *) &handle_ptr)) { - *handle = *handle_ptr; - zend_hash_index_del(&list->free, index); - } else { - *handle = provider->ctor(); - } - - if (*handle) { - ++provider->list.used; - ++list->used; - return SUCCESS; - } - } else { - *handle = NULL; - } - - return FAILURE; -} - -static inline STATUS http_persistent_handle_do_release(http_persistent_handle_provider *provider, void **handle TSRMLS_DC) -{ - http_persistent_handle_list *list; - - if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { - if (provider->list.used >= HTTP_G->persistent.handles.limit) { - provider->dtor(*handle); - } else { - if (SUCCESS != zend_hash_next_index_insert(&list->free, (void *) handle, sizeof(void *), NULL)) { - return FAILURE; - } - } - - *handle = NULL; - --provider->list.used; - --list->used; - return SUCCESS; - } - - return FAILURE; -} - -static inline STATUS http_persistent_handle_do_accrete(http_persistent_handle_provider *provider, void *old_handle, void **new_handle TSRMLS_DC) -{ - http_persistent_handle_list *list; - - if (provider->copy && (*new_handle = provider->copy(old_handle))) { - if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { - ++list->used; - } - ++provider->list.used; - return SUCCESS; - } - return FAILURE; -} - -static void http_persistent_handles_hash_dtor(void *p) -{ - http_persistent_handle_provider *provider = (http_persistent_handle_provider *) p; - http_persistent_handle_list **list, *list_tmp; - HashPosition pos; - - FOREACH_HASH_VAL(pos, &provider->list.free, list) { - /* fix shutdown crash in PHP4 */ - list_tmp = *list; - http_persistent_handle_list_free(&list_tmp, provider->dtor); - } - - zend_hash_destroy(&provider->list.free); -} - -PHP_MINIT_FUNCTION(http_persistent_handle) -{ - zend_hash_init(&http_persistent_handles_hash, 0, NULL, http_persistent_handles_hash_dtor, 1); -#ifdef ZTS - http_persistent_handles_lock = tsrm_mutex_alloc(); -#endif - return SUCCESS; -} - -PHP_MSHUTDOWN_FUNCTION(http_persistent_handle) -{ - zend_hash_destroy(&http_persistent_handles_hash); -#ifdef ZTS - tsrm_mutex_free(http_persistent_handles_lock); -#endif - return SUCCESS; -} - -PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, size_t name_len, http_persistent_handle_ctor ctor, http_persistent_handle_dtor dtor, http_persistent_handle_copy copy) -{ - STATUS status = FAILURE; - http_persistent_handle_provider provider; - - LOCK(); - if (http_persistent_handle_list_init(&provider.list)) { - provider.ctor = ctor; - provider.dtor = dtor; - provider.copy = copy; - -#if HTTP_DEBUG_PHANDLES - fprintf(stderr, "PROVIDE: %s\n", name_str); -#endif - - if (SUCCESS == zend_hash_add(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider, sizeof(http_persistent_handle_provider), NULL)) { - status = SUCCESS; - } - } - UNLOCK(); - - return status; -} - -PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC) -{ - STATUS status = FAILURE; - http_persistent_handle_provider *provider; - - *handle = NULL; - LOCK(); - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) { - status = http_persistent_handle_do_acquire(provider, handle TSRMLS_CC); - } - UNLOCK(); - -#if HTTP_DEBUG_PHANDLES - fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle, name_str); -#endif - - return status; -} - -PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC) -{ - STATUS status = FAILURE; - http_persistent_handle_provider *provider; -#if HTTP_DEBUG_PHANDLES - void *handle_tmp = *handle; -#endif - - LOCK(); - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) { - status = http_persistent_handle_do_release(provider, handle TSRMLS_CC); - } - UNLOCK(); - -#if HTTP_DEBUG_PHANDLES - fprintf(stderr, "RELEASE: %p (%s)\n", handle_tmp, name_str); -#endif - - return status; -} - -PHP_HTTP_API STATUS _http_persistent_handle_accrete_ex(const char *name_str, size_t name_len, void *old_handle, void **new_handle TSRMLS_DC) -{ - STATUS status = FAILURE; - http_persistent_handle_provider *provider; - - *new_handle = NULL; - LOCK(); - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) { - status = http_persistent_handle_do_accrete(provider, old_handle, new_handle TSRMLS_CC); - } - UNLOCK(); - -#if HTTP_DEBUG_PHANDLES - fprintf(stderr, "ACCRETE: %p > %p (%s)\n", old_handle, *new_handle, name_str); -#endif - - return status; -} - -PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC) -{ - http_persistent_handle_provider *provider; - http_persistent_handle_list *list, **listp; - HashPosition pos1, pos2; - - LOCK(); - if (name_str && name_len) { - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) { - if (current_ident_only) { - if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { - http_persistent_handle_list_dtor(list, provider->dtor); - http_persistent_handle_list_init(list); - } - } else { - FOREACH_HASH_VAL(pos1, &provider->list.free, listp) { - http_persistent_handle_list_dtor(*listp, provider->dtor); - http_persistent_handle_list_init(*listp); - } - } - } - } else { - FOREACH_HASH_VAL(pos1, &http_persistent_handles_hash, provider) { - if (current_ident_only) { - if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { - http_persistent_handle_list_dtor(list, provider->dtor); - http_persistent_handle_list_init(list); - } - } else { - FOREACH_HASH_VAL(pos2, &provider->list.free, listp) { - http_persistent_handle_list_dtor(*listp, provider->dtor); - http_persistent_handle_list_init(*listp); - } - } - } - } - UNLOCK(); -} - -PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht TSRMLS_DC) -{ - zval *zentry[2]; - HashPosition pos1, pos2; - HashKey key1 = initHashKey(0), key2 = initHashKey(0); - http_persistent_handle_provider *provider; - http_persistent_handle_list **list; - - LOCK(); - if (zend_hash_num_elements(&http_persistent_handles_hash)) { - if (!ht) { - ALLOC_HASHTABLE(ht); - zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0); - } - - FOREACH_HASH_KEYVAL(pos1, &http_persistent_handles_hash, key1, provider) { - MAKE_STD_ZVAL(zentry[0]); - array_init(zentry[0]); - - FOREACH_HASH_KEYVAL(pos2, &provider->list.free, key2, list) { - MAKE_STD_ZVAL(zentry[1]); - array_init(zentry[1]); - add_assoc_long_ex(zentry[1], ZEND_STRS("used"), (*list)->used); - add_assoc_long_ex(zentry[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list)->free)); - - /* use zend_hash_* not add_assoc_* (which is zend_symtable_*) as we want a string even for numbers */ - zend_hash_add(Z_ARRVAL_P(zentry[0]), key2.str, key2.len, &zentry[1], sizeof(zval *), NULL); - } - - zend_hash_add(ht, key1.str, key1.len, &zentry[0], sizeof(zval *), NULL); - } - } else if (ht) { - ht = NULL; - } - UNLOCK(); - - return ht; -} - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_querystring_api.c b/http_querystring_api.c deleted file mode 100644 index 7caa7bc..0000000 --- a/http_querystring_api.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#include "php_http.h" - -#include "php_variables.h" -#ifdef HTTP_HAVE_ICONV -# undef PHP_ATOM_INC -# include "ext/iconv/php_iconv.h" -# include "ext/standard/url.h" -#endif - -#include "php_http_api.h" -#include "php_http_url_api.h" -#include "php_http_querystring_api.h" - -#ifdef ZEND_ENGINE_2 -#define THIS_CE http_querystring_object_ce -extern zend_class_entry *http_querystring_object_ce; -#endif - - -#define http_querystring_modify_array_ex(q, t, k, kl, i, pe) _http_querystring_modify_array_ex((q), (t), (k), (kl), (i), (pe) TSRMLS_CC) -static inline int _http_querystring_modify_array_ex(zval *qarray, int key_type, char *key, int keylen, ulong idx, zval *params_entry TSRMLS_DC); -#define http_querystring_modify_array(q, p) _http_querystring_modify_array((q), (p) TSRMLS_CC) -static inline int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC); - - -#ifdef HTTP_HAVE_ICONV -PHP_HTTP_API int _http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC) -{ - HashPosition pos; - zval **entry = NULL; - char *xlate_str = NULL, *xkey; - size_t xlate_len = 0, xlen; - HashKey key = initHashKey(0); - - FOREACH_KEYVAL(pos, param, key, entry) { - if (key.type == HASH_KEY_IS_STRING) { - if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.str, key.len-1, &xkey, &xlen, oe, ie)) { - http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", key.len-1, key.str, ie, oe); - return FAILURE; - } - } - - if (Z_TYPE_PP(entry) == IS_STRING) { - if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), &xlate_str, &xlate_len, oe, ie)) { - if (key.type == HASH_KEY_IS_STRING) { - efree(xkey); - } - http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_PP(entry), Z_STRVAL_PP(entry), ie, oe); - return FAILURE; - } - if (key.type == HASH_KEY_IS_STRING) { - add_assoc_stringl_ex(array, xkey, xlen+1, xlate_str, xlate_len, 0); - } else { - add_index_stringl(array, key.num, xlate_str, xlate_len, 0); - } - } else if (Z_TYPE_PP(entry) == IS_ARRAY) { - zval *subarray; - - MAKE_STD_ZVAL(subarray); - array_init(subarray); - if (key.type == HASH_KEY_IS_STRING) { - add_assoc_zval_ex(array, xkey, xlen+1, subarray); - } else { - add_index_zval(array, key.num, subarray); - } - if (SUCCESS != http_querystring_xlate(subarray, *entry, ie, oe)) { - if (key.type == HASH_KEY_IS_STRING) { - efree(xkey); - } - return FAILURE; - } - } - - if (key.type == HASH_KEY_IS_STRING) { - efree(xkey); - } - } - return SUCCESS; -} -#endif /* HAVE_ICONV */ - -PHP_HTTP_API void _http_querystring_update(zval *qarray, zval *qstring TSRMLS_DC) -{ - char *s = NULL; - size_t l = 0; - - if (Z_TYPE_P(qarray) != IS_ARRAY) { - convert_to_array(qarray); - } - if (SUCCESS == http_urlencode_hash_ex(Z_ARRVAL_P(qarray), 0, NULL, 0, &s, &l)) { - zval_dtor(qstring); - ZVAL_STRINGL(qstring, s, l, 0); - } else { - http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to update query string"); - } -} - -PHP_HTTP_API int _http_querystring_modify(zval *qarray, zval *params TSRMLS_DC) -{ - if (Z_TYPE_P(params) == IS_ARRAY) { - return http_querystring_modify_array(qarray, params); - } else if (Z_TYPE_P(params) == IS_OBJECT) { -#ifdef ZEND_ENGINE_2 - if (instanceof_function(Z_OBJCE_P(params), http_querystring_object_ce TSRMLS_CC)) { - return http_querystring_modify_array(qarray, zend_read_property(THIS_CE, params, ZEND_STRS("queryArray")-1, 0 TSRMLS_CC)); - } else { -#endif - return http_querystring_modify_array(qarray, params); -#ifdef ZEND_ENGINE_2 - } -#endif - } else { - int rv; - zval array; - zval *qstring = http_zsep(IS_STRING, params); - - INIT_PZVAL(&array); - array_init(&array); - - sapi_module.treat_data(PARSE_STRING, estrdup(Z_STRVAL_P(qstring)), &array TSRMLS_CC); - zval_ptr_dtor(&qstring); - - rv = http_querystring_modify_array(qarray, &array); - zval_dtor(&array); - return rv; - } -} - -static inline int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC) -{ - int rv = 0; - HashKey key = initHashKey(0); - HashPosition pos; - zval **params_entry = NULL; - - FOREACH_HASH_KEYVAL(pos, HASH_OF(params), key, params_entry) { - /* only public properties */ - if ((key.type != HASH_KEY_IS_STRING || *key.str) && http_querystring_modify_array_ex(qarray, key.type, key.str, key.len, key.num, *params_entry)) { - rv = 1; - } - } - - return rv; -} - -static inline int _http_querystring_modify_array_ex(zval *qarray, int key_type, char *key, int keylen, ulong idx, zval *params_entry TSRMLS_DC) -{ - zval **qarray_entry; - - /* ensure array type */ - if (Z_TYPE_P(qarray) != IS_ARRAY) { - convert_to_array(qarray); - } - - /* delete */ - if (Z_TYPE_P(params_entry) == IS_NULL) { - if (key_type == HASH_KEY_IS_STRING) { - return (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), key, keylen)); - } else { - return (SUCCESS == zend_hash_index_del(Z_ARRVAL_P(qarray), idx)); - } - } - - /* update */ - if ( ((key_type == HASH_KEY_IS_STRING) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), key, keylen, (void *) &qarray_entry))) || - ((key_type == HASH_KEY_IS_LONG) && (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(qarray), idx, (void *) &qarray_entry)))) { - zval equal; - - /* recursive */ - if (Z_TYPE_P(params_entry) == IS_ARRAY || Z_TYPE_P(params_entry) == IS_OBJECT) { - return http_querystring_modify(*qarray_entry, params_entry); - } - /* equal */ - if ((SUCCESS == is_equal_function(&equal, *qarray_entry, params_entry TSRMLS_CC)) && Z_BVAL(equal)) { - return 0; - } - } - - /* add */ - if (Z_TYPE_P(params_entry) == IS_OBJECT) { - zval *new_array; - - MAKE_STD_ZVAL(new_array); - array_init(new_array); - http_querystring_modify_array(new_array, params_entry); - params_entry = new_array; - } else { - ZVAL_ADDREF(params_entry); - } - if (key_type == HASH_KEY_IS_STRING) { - add_assoc_zval_ex(qarray, key, keylen, params_entry); - } else { - add_index_zval(qarray, idx, params_entry); - } - return 1; -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/http_querystring_object.c b/http_querystring_object.c deleted file mode 100644 index 4c82eda..0000000 --- a/http_querystring_object.c +++ /dev/null @@ -1,633 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#include "php_http.h" - -#ifdef ZEND_ENGINE_2 - -#include "php_variables.h" -#include "zend_interfaces.h" - -#include "php_http_api.h" -#include "php_http_querystring_api.h" -#include "php_http_querystring_object.h" -#include "php_http_exception_object.h" - -#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpQueryString, method, 0, req_args) -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpQueryString, method, 0) -#define HTTP_QUERYSTRING_ME(method, visibility) PHP_ME(HttpQueryString, method, HTTP_ARGS(HttpQueryString, method), visibility) -#define HTTP_QUERYSTRING_GME(method, visibility) PHP_ME(HttpQueryString, method, HTTP_ARGS(HttpQueryString, __getter), visibility) - -HTTP_BEGIN_ARGS(__construct, 0) - HTTP_ARG_VAL(global, 0) - HTTP_ARG_VAL(params, 0) -HTTP_END_ARGS; - -#ifndef WONKY -HTTP_BEGIN_ARGS(singleton, 0) - HTTP_ARG_VAL(global, 0) -HTTP_END_ARGS; -#endif - -HTTP_BEGIN_ARGS(factory, 0) - HTTP_ARG_VAL(global, 0) - HTTP_ARG_VAL(params, 0) - HTTP_ARG_VAL(class_name, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(toArray); -HTTP_EMPTY_ARGS(toString); - -HTTP_BEGIN_ARGS(get, 0) - HTTP_ARG_VAL(name, 0) - HTTP_ARG_VAL(type, 0) - HTTP_ARG_VAL(defval, 0) - HTTP_ARG_VAL(delete, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(set, 1) - HTTP_ARG_VAL(params, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(mod, 0) - HTTP_ARG_VAL(params, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(__getter, 1) - HTTP_ARG_VAL(name, 0) - HTTP_ARG_VAL(defval, 0) - HTTP_ARG_VAL(delete, 0) -HTTP_END_ARGS; - -#ifdef HTTP_HAVE_ICONV -HTTP_BEGIN_ARGS(xlate, 2) - HTTP_ARG_VAL(from_encoding, 0) - HTTP_ARG_VAL(to_encoding, 0) -HTTP_END_ARGS; -#endif - -HTTP_EMPTY_ARGS(serialize); -HTTP_BEGIN_ARGS(unserialize, 1) - HTTP_ARG_VAL(serialized, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(offsetGet, 1) - HTTP_ARG_VAL(offset, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(offsetSet, 2) - HTTP_ARG_VAL(offset, 0) - HTTP_ARG_VAL(value, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(offsetExists, 1) - HTTP_ARG_VAL(offset, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(offsetUnset, 1) - HTTP_ARG_VAL(offset, 0) -HTTP_END_ARGS; - - -#define THIS_CE http_querystring_object_ce -zend_class_entry *http_querystring_object_ce; -zend_function_entry http_querystring_object_fe[] = { - HTTP_QUERYSTRING_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL) - - HTTP_QUERYSTRING_ME(toArray, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_ME(toString, ZEND_ACC_PUBLIC) - ZEND_MALIAS(HttpQueryString, __toString, toString, HTTP_ARGS(HttpQueryString, toString), ZEND_ACC_PUBLIC) - - HTTP_QUERYSTRING_ME(get, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_ME(set, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_ME(mod, ZEND_ACC_PUBLIC) - - HTTP_QUERYSTRING_GME(getBool, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_GME(getInt, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_GME(getFloat, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_GME(getString, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_GME(getArray, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_GME(getObject, ZEND_ACC_PUBLIC) - - HTTP_QUERYSTRING_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) -#ifndef WONKY - HTTP_QUERYSTRING_ME(singleton, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) -#endif -#ifdef HTTP_HAVE_ICONV - HTTP_QUERYSTRING_ME(xlate, ZEND_ACC_PUBLIC) -#endif - - /* Implements Serializable */ - HTTP_QUERYSTRING_ME(serialize, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_ME(unserialize, ZEND_ACC_PUBLIC) - - /* Implements ArrayAccess */ - HTTP_QUERYSTRING_ME(offsetGet, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_ME(offsetSet, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_ME(offsetExists, ZEND_ACC_PUBLIC) - HTTP_QUERYSTRING_ME(offsetUnset, ZEND_ACC_PUBLIC) - - EMPTY_FUNCTION_ENTRY -}; -static zend_object_handlers http_querystring_object_handlers; - -PHP_MINIT_FUNCTION(http_querystring_object) -{ - HTTP_REGISTER_CLASS_EX(HttpQueryString, http_querystring_object, NULL, 0); - -#ifndef WONKY - zend_class_implements(http_querystring_object_ce TSRMLS_CC, 2, zend_ce_serializable, zend_ce_arrayaccess); -#endif - - zend_declare_property_null(THIS_CE, ZEND_STRS("instance")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("queryArray")-1, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(THIS_CE, ZEND_STRS("queryString")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC); - -#ifndef WONKY - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_BOOL")-1, HTTP_QUERYSTRING_TYPE_BOOL TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_INT")-1, HTTP_QUERYSTRING_TYPE_INT TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_FLOAT")-1, HTTP_QUERYSTRING_TYPE_FLOAT TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_STRING")-1, HTTP_QUERYSTRING_TYPE_STRING TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_ARRAY")-1, HTTP_QUERYSTRING_TYPE_ARRAY TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("TYPE_OBJECT")-1, HTTP_QUERYSTRING_TYPE_OBJECT TSRMLS_CC); -#endif - - HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_BOOL", HTTP_QUERYSTRING_TYPE_BOOL); - HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_INT", HTTP_QUERYSTRING_TYPE_INT); - HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_FLOAT", HTTP_QUERYSTRING_TYPE_FLOAT); - HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_STRING", HTTP_QUERYSTRING_TYPE_STRING); - HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_ARRAY", HTTP_QUERYSTRING_TYPE_ARRAY); - HTTP_LONG_CONSTANT("HTTP_QUERYSTRING_TYPE_OBJECT", HTTP_QUERYSTRING_TYPE_OBJECT); - - return SUCCESS; -} - -zend_object_value _http_querystring_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return http_querystring_object_new_ex(ce, NULL, NULL); -} - -zend_object_value _http_querystring_object_new_ex(zend_class_entry *ce, void *nothing, http_querystring_object **ptr TSRMLS_DC) -{ - zend_object_value ov; - http_querystring_object *o; - - o = ecalloc(1, sizeof(http_querystring_object)); - o->zo.ce = ce; - - if (ptr) { - *ptr = o; - } - -#ifdef ZEND_ENGINE_2_4 - zend_object_std_init(o, ce TSRMLS_CC); - object_properties_init(o, ce); -#else - ALLOC_HASHTABLE(OBJ_PROP(o)); - zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); -#endif - - ov.handle = putObject(http_querystring_object, o); - ov.handlers = &http_querystring_object_handlers; - - return ov; -} - -void _http_querystring_object_free(zend_object *object TSRMLS_DC) -{ - http_querystring_object *o = (http_querystring_object *) object; - - freeObject(o); -} - -/* {{{ querystring helpers */ -#define http_querystring_instantiate(t, g, p, u) _http_querystring_instantiate((t), (g), (p), (u) TSRMLS_CC) -static inline zval *_http_querystring_instantiate(zval *this_ptr, zend_bool global, zval *params, zend_bool defer_update TSRMLS_DC) -{ - zval *qarray = NULL, *qstring = NULL, **_SERVER = NULL, **_GET = NULL, **QUERY_STRING = NULL;; - - if (!this_ptr) { - MAKE_STD_ZVAL(this_ptr); - Z_TYPE_P(this_ptr) = IS_OBJECT; - this_ptr->value.obj = http_querystring_object_new(http_querystring_object_ce); - } - if (global) { -#ifdef ZEND_ENGINE_2 - zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC); -#endif - if ( (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &_SERVER)) && - (Z_TYPE_PP(_SERVER) == IS_ARRAY) && - (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "QUERY_STRING", sizeof("QUERY_STRING"), (void *) &QUERY_STRING))) { - - qstring = *QUERY_STRING; -#ifdef ZEND_ENGINE_2 - zend_is_auto_global("_GET", lenof("_GET") TSRMLS_CC); -#endif - if ((SUCCESS == zend_hash_find(&EG(symbol_table), "_GET", sizeof("_GET"), (void *) &_GET)) && (Z_TYPE_PP(_GET) == IS_ARRAY)) { - qarray = *_GET; - } else { - http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Could not acquire reference to superglobal GET array"); - } - } else { - http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Could not acquire reference to QUERY_STRING"); - } - - if (qarray && qstring) { - if (Z_TYPE_P(qstring) != IS_STRING) { - convert_to_string(qstring); - } - - zend_update_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, qarray TSRMLS_CC); - zend_update_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, qstring TSRMLS_CC); -#ifdef Z_SET_ISREF - Z_SET_ISREF_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC)); - Z_SET_ISREF_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC)); -#else - zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC)->is_ref = 1; - zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC)->is_ref = 1; -#endif - - if (params) { - http_querystring_modify(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC), params); - } - if (!defer_update) { - http_querystring_update(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC), zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC)); - } - } - } else { - MAKE_STD_ZVAL(qarray); - array_init(qarray); - - zend_update_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, qarray TSRMLS_CC); - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("queryString")-1, "", 0 TSRMLS_CC); - - if (params && http_querystring_modify(qarray, params) && !defer_update) { - http_querystring_update(qarray, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC)); - } - - zval_ptr_dtor(&qarray); - } - - return this_ptr; -} - -#define http_querystring_get(o, t, n, l, def, del, r) _http_querystring_get((o), (t), (n), (l), (def), (del), (r) TSRMLS_CC) -static inline void _http_querystring_get(zval *this_ptr, int type, char *name, uint name_len, zval *defval, zend_bool del, zval *return_value TSRMLS_DC) -{ - zval **arrval, *qarray = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC); - - if ((Z_TYPE_P(qarray) == IS_ARRAY) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), name, name_len + 1, (void *) &arrval))) { - if (type) { - zval *value = http_zsep(type, *arrval); - RETVAL_ZVAL(value, 1, 1); - } else { - RETVAL_ZVAL(*arrval, 1, 0); - } - - if (del && (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarray), name, name_len + 1))) { - http_querystring_update(qarray, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC)); - } - } else if(defval) { - RETURN_ZVAL(defval, 1, 0); - } -} -/* }}} */ - -/* {{{ proto final void HttpQueryString::__construct([bool global = true[, mixed add]) - Creates a new HttpQueryString object instance. Operates on and modifies $_GET and $_SERVER['QUERY_STRING'] if global is TRUE. */ -PHP_METHOD(HttpQueryString, __construct) -{ - zend_bool global = 1; - zval *params = NULL; - - SET_EH_THROW_HTTP(); - if (!sapi_module.treat_data) { - http_error(HE_ERROR, HTTP_E_QUERYSTRING, "The SAPI does not have a treat_data function registered"); - } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bz", &global, ¶ms)) { - http_querystring_instantiate(getThis(), global, params, 0); - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto HttpQueryString HttpQueryString::factory([bool global = TRUE[, mixed params[, string class_name = "HttpQueryString"]) - Creates a new HttpQueryString object instance. */ -PHP_METHOD(HttpQueryString, factory) -{ - zend_bool global = 1; - zval *params = NULL; - char *cn = NULL; - int cl = 0; - zend_object_value ov; - - SET_EH_THROW_HTTP(); - if (!sapi_module.treat_data) { - http_error(HE_ERROR, HTTP_E_QUERYSTRING, "The SAPI does not have a treat_data function registered"); - } else if ( SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bzs", &global, ¶ms, &cn, &cl) && - SUCCESS == http_object_new(&ov, cn, cl, _http_querystring_object_new_ex, http_querystring_object_ce, NULL, NULL)) { - RETVAL_OBJVAL(ov, 0); - http_querystring_instantiate(return_value, global, params, 0); - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto string HttpQueryString::toString() - Returns the string representation. */ -PHP_METHOD(HttpQueryString, toString) -{ - NO_ARGS; - RETURN_PROP(queryString); -} -/* }}} */ - -/* {{{ proto array HttpQueryString::toArray() - Returns the array representation. */ -PHP_METHOD(HttpQueryString, toArray) -{ - NO_ARGS; - RETURN_PROP(queryArray); -} -/* }}} */ - -/* {{{ proto mixed HttpQueryString::get([string key[, mixed type = 0[, mixed defval = NULL[, bool delete = false]]]]) - Get (part of) the query string. The type parameter is either one of the HttpQueryString::TYPE_* constants or a type abbreviation like "b" for bool, "i" for int, "f" for float, "s" for string, "a" for array and "o" for a stdClass object. */ -PHP_METHOD(HttpQueryString, get) -{ - char *name = NULL; - int name_len = 0; - long type = 0; - zend_bool del = 0; - zval *ztype = NULL, *defval = NULL; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|szzb", &name, &name_len, &ztype, &defval, &del)) { - if (name && name_len) { - if (ztype) { - if (Z_TYPE_P(ztype) == IS_LONG) { - type = Z_LVAL_P(ztype); - } else if(Z_TYPE_P(ztype) == IS_STRING) { - switch (Z_STRVAL_P(ztype)[0]) { - case 'B': - case 'b': type = HTTP_QUERYSTRING_TYPE_BOOL; break; - case 'I': - case 'i': type = HTTP_QUERYSTRING_TYPE_INT; break; - case 'F': - case 'f': type = HTTP_QUERYSTRING_TYPE_FLOAT; break; - case 'S': - case 's': type = HTTP_QUERYSTRING_TYPE_STRING; break; - case 'A': - case 'a': type = HTTP_QUERYSTRING_TYPE_ARRAY; break; - case 'O': - case 'o': type = HTTP_QUERYSTRING_TYPE_OBJECT; break; - } - } - } - http_querystring_get(getThis(), type, name, name_len, defval, del, return_value); - } else { - RETURN_PROP(queryString); - } - } -} -/* }}} */ - -/* {{{ proto string HttpQueryString::set(mixed params) - Set query string entry/entries. NULL values will unset the variable. */ -PHP_METHOD(HttpQueryString, set) -{ - zval *params; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶ms)) { - zval *qarray = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC); - if (http_querystring_modify(qarray, params)) { - http_querystring_update(qarray, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC)); - } - } - - if (return_value_used) { - RETURN_PROP(queryString); - } -} -/* }}} */ - -/* {{{ proto HttpQueryString HttpQueryString::mod(mixed params) - Copies the query string object and sets provided params at the clone. */ -PHP_METHOD(HttpQueryString, mod) -{ - zval *zobj, *qarr, *qstr, *params; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶ms)) { - zobj = http_querystring_instantiate(NULL, 0, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC), 1); - qarr = zend_read_property(THIS_CE, zobj, ZEND_STRS("queryArray")-1, 0 TSRMLS_CC); - qstr = zend_read_property(THIS_CE, zobj, ZEND_STRS("queryString")-1, 0 TSRMLS_CC); - - http_querystring_modify(qarr, params); - http_querystring_update(qarr, qstr); - - RETURN_ZVAL(zobj, 1, 1); - } -} -/* }}} */ - -#ifndef WONKY -/* {{{ proto static HttpQueryString HttpQueryString::singleton([bool global = true]) - Get a single instance (differentiates between the global setting). */ -PHP_METHOD(HttpQueryString, singleton) -{ - zend_bool global = 1; - zval *instance = *zend_std_get_static_property(THIS_CE, ZEND_STRS("instance")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC); - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &global)) { - zval **zobj_ptr = NULL, *zobj = NULL; - - if (Z_TYPE_P(instance) == IS_ARRAY) { - if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(instance), global, (void *) &zobj_ptr)) { - RETVAL_ZVAL(*zobj_ptr, 1, 0); - } else { - zobj = http_querystring_instantiate(NULL, global, NULL, (zend_bool) !global); - add_index_zval(instance, global, zobj); - RETVAL_OBJECT(zobj, 1); - } - } else { - MAKE_STD_ZVAL(instance); - array_init(instance); - - zobj = http_querystring_instantiate(NULL, global, NULL, (zend_bool) !global); - add_index_zval(instance, global, zobj); - RETVAL_OBJECT(zobj, 1); - - zend_update_static_property(THIS_CE, ZEND_STRS("instance")-1, instance TSRMLS_CC); - zval_ptr_dtor(&instance); - } - } - SET_EH_NORMAL(); -} -/* }}} */ -#endif - -/* {{{ Getters by type */ -#define HTTP_QUERYSTRING_GETTER(method, TYPE) \ -PHP_METHOD(HttpQueryString, method) \ -{ \ - char *name; \ - int name_len; \ - zval *defval = NULL; \ - zend_bool del = 0; \ - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zb", &name, &name_len, &defval, &del)) { \ - http_querystring_get(getThis(), TYPE, name, name_len, defval, del, return_value); \ - } \ -} -HTTP_QUERYSTRING_GETTER(getBool, IS_BOOL); -HTTP_QUERYSTRING_GETTER(getInt, IS_LONG); -HTTP_QUERYSTRING_GETTER(getFloat, IS_DOUBLE); -HTTP_QUERYSTRING_GETTER(getString, IS_STRING); -HTTP_QUERYSTRING_GETTER(getArray, IS_ARRAY); -HTTP_QUERYSTRING_GETTER(getObject, IS_OBJECT); -/* }}} */ - -#ifdef HTTP_HAVE_ICONV -/* {{{ proto bool HttpQueryString::xlate(string ie, string oe) - Converts the query string from the source encoding ie to the target encoding oe. WARNING: Don't use any character set that can contain NUL bytes like UTF-16. */ -PHP_METHOD(HttpQueryString, xlate) -{ - char *ie, *oe; - int ie_len, oe_len; - zval xa, *qa, *qs; - STATUS rs; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &ie, &ie_len, &oe, &oe_len)) { - RETURN_FALSE; - } - - qa = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC); - qs = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC); - INIT_PZVAL(&xa); - array_init(&xa); - - if (SUCCESS == (rs = http_querystring_xlate(&xa, qa, ie, oe))) { - zend_hash_clean(Z_ARRVAL_P(qa)); - zend_hash_copy(Z_ARRVAL_P(qa), Z_ARRVAL(xa), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - http_querystring_update(qa, qs); - } - zval_dtor(&xa); - - RETURN_SUCCESS(rs); -} -/* }}} */ -#endif /* HAVE_ICONV */ - -/* {{{ proto string HttpQueryString::serialize() - Implements Serializable::serialize(). */ -PHP_METHOD(HttpQueryString, serialize) -{ - NO_ARGS; - RETURN_PROP(queryString); -} -/* }}} */ - -/* {{{ proto void HttpQueryString::unserialize(string serialized) - Implements Serializable::unserialize(). */ -PHP_METHOD(HttpQueryString, unserialize) -{ - zval *serialized; - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &serialized)) { - if (Z_TYPE_P(serialized) == IS_STRING) { - http_querystring_instantiate(getThis(), 0, serialized, 0); - } else { - http_error(HE_WARNING, HTTP_E_QUERYSTRING, "Expected a string as parameter"); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto mixed HttpQueryString::offsetGet(string offset) - Implements ArrayAccess::offsetGet(). */ -PHP_METHOD(HttpQueryString, offsetGet) -{ - char *offset_str; - int offset_len; - zval **value; - - if ( (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) && - (SUCCESS == zend_hash_find(Z_ARRVAL_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC)), offset_str, offset_len + 1, (void *) &value))) { - RETVAL_ZVAL(*value, 1, 0); - } -} -/* }}} */ - -/* {{{ proto void HttpQueryString::offsetSet(string offset, mixed value) - Implements ArrayAccess::offsetGet(). */ -PHP_METHOD(HttpQueryString, offsetSet) -{ - char *offset_str; - int offset_len; - zval *value; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &offset_str, &offset_len, &value)) { - zval *qarr = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC), *qstr = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC); - - ZVAL_ADDREF(value); - add_assoc_zval_ex(qarr, offset_str, offset_len + 1, value); - http_querystring_update(qarr, qstr); - } -} -/* }}} */ - -/* {{{ proto bool HttpQueryString::offsetExists(string offset) - Implements ArrayAccess::offsetExists(). */ -PHP_METHOD(HttpQueryString, offsetExists) -{ - char *offset_str; - int offset_len; - zval **value; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) { - RETURN_BOOL((SUCCESS == zend_hash_find(Z_ARRVAL_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC)), offset_str, offset_len + 1, (void *) &value)) && (Z_TYPE_PP(value) != IS_NULL)); - } -} -/* }}} */ - -/* {{{ proto void HttpQueryString::offsetUnset(string offset) - Implements ArrayAccess::offsetUnset(). */ -PHP_METHOD(HttpQueryString, offsetUnset) -{ - char *offset_str; - int offset_len; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) { - zval *qarr = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryArray")-1, 0 TSRMLS_CC); - - if (SUCCESS == zend_hash_del(Z_ARRVAL_P(qarr), offset_str, offset_len + 1)) { - http_querystring_update(qarr, zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryString")-1, 0 TSRMLS_CC)); - } - } -} -/* }}} */ - -#endif /* ZEND_ENGINE_2 */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_request_api.c b/http_request_api.c deleted file mode 100644 index b6e4034..0000000 --- a/http_request_api.c +++ /dev/null @@ -1,1343 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#define HTTP_WANT_CURL -#include "php_http.h" - -#ifdef HTTP_HAVE_CURL - -#include "php_http_api.h" -#include "php_http_persistent_handle_api.h" -#include "php_http_request_api.h" -#include "php_http_url_api.h" - -#ifdef ZEND_ENGINE_2 -# include "php_http_request_object.h" -#endif - -#include "php_http_request_int.h" - -/* {{{ cruft for thread safe SSL crypto locks */ -#ifdef HTTP_NEED_OPENSSL_TSL -static MUTEX_T *http_openssl_tsl = NULL; - -static void http_openssl_thread_lock(int mode, int n, const char * file, int line) -{ - if (mode & CRYPTO_LOCK) { - tsrm_mutex_lock(http_openssl_tsl[n]); - } else { - tsrm_mutex_unlock(http_openssl_tsl[n]); - } -} - -static ulong http_openssl_thread_id(void) -{ - return (ulong) tsrm_thread_id(); -} -#endif -#ifdef HTTP_NEED_GNUTLS_TSL -static int http_gnutls_mutex_create(void **m) -{ - if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) { - return SUCCESS; - } else { - return FAILURE; - } -} - -static int http_gnutls_mutex_destroy(void **m) -{ - tsrm_mutex_free(*((MUTEX_T *) m)); - return SUCCESS; -} - -static int http_gnutls_mutex_lock(void **m) -{ - return tsrm_mutex_lock(*((MUTEX_T *) m)); -} - -static int http_gnutls_mutex_unlock(void **m) -{ - return tsrm_mutex_unlock(*((MUTEX_T *) m)); -} - -static struct gcry_thread_cbs http_gnutls_tsl = { - GCRY_THREAD_OPTION_USER, - NULL, - http_gnutls_mutex_create, - http_gnutls_mutex_destroy, - http_gnutls_mutex_lock, - http_gnutls_mutex_unlock -}; -#endif -/* }}} */ - -/* safe curl wrappers */ -#define init_curl_storage(ch) \ - {\ - http_request_storage *st = pecalloc(1, sizeof(http_request_storage), 1); \ - curl_easy_setopt(ch, CURLOPT_PRIVATE, st); \ - curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer); \ - } - -static void *safe_curl_init(void) -{ - CURL *ch; - - if ((ch = curl_easy_init())) { - init_curl_storage(ch); - return ch; - } - return NULL; -} -static void *safe_curl_copy(void *p) -{ - CURL *ch; - - if ((ch = curl_easy_duphandle(p))) { - init_curl_storage(ch); - return ch; - } - return NULL; -} -static void safe_curl_dtor(void *p) { - http_request_storage *st = http_request_storage_get(p); - - curl_easy_cleanup(p); - - if (st) { - if (st->url) { - pefree(st->url, 1); - } - if (st->cookiestore) { - pefree(st->cookiestore, 1); - } - pefree(st, 1); - } -} -/* }}} */ - -/* {{{ MINIT */ -PHP_MINIT_FUNCTION(http_request) -{ -#ifdef HTTP_NEED_OPENSSL_TSL - /* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */ - if (!CRYPTO_get_id_callback()) { - int i, c = CRYPTO_num_locks(); - - http_openssl_tsl = malloc(c * sizeof(MUTEX_T)); - - for (i = 0; i < c; ++i) { - http_openssl_tsl[i] = tsrm_mutex_alloc(); - } - - CRYPTO_set_id_callback(http_openssl_thread_id); - CRYPTO_set_locking_callback(http_openssl_thread_lock); - } -#endif -#ifdef HTTP_NEED_GNUTLS_TSL - gcry_control(GCRYCTL_SET_THREAD_CBS, &http_gnutls_tsl); -#endif - - if (CURLE_OK != curl_global_init(CURL_GLOBAL_ALL)) { - return FAILURE; - } - - if (SUCCESS != http_persistent_handle_provide("http_request", safe_curl_init, safe_curl_dtor, safe_curl_copy)) { - return FAILURE; - } - - HTTP_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC); - HTTP_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST); -#if HTTP_CURL_VERSION(7,19,3) - HTTP_LONG_CONSTANT("HTTP_AUTH_DIGEST_IE", CURLAUTH_DIGEST_IE); -#endif - HTTP_LONG_CONSTANT("HTTP_AUTH_NTLM", CURLAUTH_NTLM); - HTTP_LONG_CONSTANT("HTTP_AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE); - HTTP_LONG_CONSTANT("HTTP_AUTH_ANY", CURLAUTH_ANY); - - HTTP_LONG_CONSTANT("HTTP_VERSION_NONE", CURL_HTTP_VERSION_NONE); /* to be removed */ - HTTP_LONG_CONSTANT("HTTP_VERSION_1_0", CURL_HTTP_VERSION_1_0); - HTTP_LONG_CONSTANT("HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1); - HTTP_LONG_CONSTANT("HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE); - - HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_TLSv1", CURL_SSLVERSION_TLSv1); - HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2); - HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3); - HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT); - - HTTP_LONG_CONSTANT("HTTP_IPRESOLVE_V4", CURL_IPRESOLVE_V4); - HTTP_LONG_CONSTANT("HTTP_IPRESOLVE_V6", CURL_IPRESOLVE_V6); - HTTP_LONG_CONSTANT("HTTP_IPRESOLVE_ANY", CURL_IPRESOLVE_WHATEVER); - -#if HTTP_CURL_VERSION(7,15,2) - HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS4", CURLPROXY_SOCKS4); -#endif -#if HTTP_CURL_VERSION(7,18,0) - HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS4A", CURLPROXY_SOCKS4A); - HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS5_HOSTNAME", CURLPROXY_SOCKS5_HOSTNAME); -#endif - HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS5", CURLPROXY_SOCKS5); - HTTP_LONG_CONSTANT("HTTP_PROXY_HTTP", CURLPROXY_HTTP); -#if HTTP_CURL_VERSION(7,19,4) - HTTP_LONG_CONSTANT("HTTP_PROXY_HTTP_1_0", CURLPROXY_HTTP_1_0); -#endif - -#if HTTP_CURL_VERSION(7,19,1) - HTTP_LONG_CONSTANT("HTTP_POSTREDIR_301", CURL_REDIR_POST_301); - HTTP_LONG_CONSTANT("HTTP_POSTREDIR_302", CURL_REDIR_POST_302); - HTTP_LONG_CONSTANT("HTTP_POSTREDIR_ALL", CURL_REDIR_POST_ALL); -#endif - return SUCCESS; -} -/* }}} */ - -/* {{{ MSHUTDOWN */ -PHP_MSHUTDOWN_FUNCTION(http_request) -{ - curl_global_cleanup(); -#ifdef HTTP_NEED_OPENSSL_TSL - if (http_openssl_tsl) { - int i, c = CRYPTO_num_locks(); - - CRYPTO_set_id_callback(NULL); - CRYPTO_set_locking_callback(NULL); - - for (i = 0; i < c; ++i) { - tsrm_mutex_free(http_openssl_tsl[i]); - } - - free(http_openssl_tsl); - http_openssl_tsl = NULL; - } -#endif - return SUCCESS; -} -/* }}} */ - -/* {{{ forward declarations */ -#define http_request_option(r, o, k, t) _http_request_option_ex((r), (o), (k), sizeof(k), (t) TSRMLS_CC) -#define http_request_option_ex(r, o, k, l, t) _http_request_option_ex((r), (o), (k), (l), (t) TSRMLS_CC) -static inline zval *_http_request_option_ex(http_request *request, HashTable *options, char *key, size_t keylen, int type TSRMLS_DC); -#define http_request_option_cache(r, k, z) _http_request_option_cache_ex((r), (k), sizeof(k), 0, (z) TSRMLS_CC) -#define http_request_option_cache_ex(r, k, kl, h, z) _http_request_option_cache_ex((r), (k), (kl), (h), (z) TSRMLS_CC) -static inline zval *_http_request_option_cache_ex(http_request *r, char *key, size_t keylen, ulong h, zval *opt TSRMLS_DC); - -#define http_request_cookies_enabled(r) _http_request_cookies_enabled((r)) -static inline int _http_request_cookies_enabled(http_request *r); - -static size_t http_curl_read_callback(void *, size_t, size_t, void *); -static int http_curl_progress_callback(void *, double, double, double, double); -static int http_curl_raw_callback(CURL *, curl_infotype, char *, size_t, void *); -static int http_curl_dummy_callback(char *data, size_t n, size_t l, void *s) { return n*l; } -static curlioerr http_curl_ioctl_callback(CURL *, curliocmd, void *); -/* }}} */ - -/* {{{ CURL *http_curl_init(http_request *) */ -PHP_HTTP_API CURL * _http_curl_init_ex(CURL *ch, http_request *request TSRMLS_DC) -{ - if (ch || (SUCCESS == http_persistent_handle_acquire("http_request", &ch))) { -#if defined(ZTS) - curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); -#endif - curl_easy_setopt(ch, CURLOPT_HEADER, 0L); - curl_easy_setopt(ch, CURLOPT_FILETIME, 1L); - curl_easy_setopt(ch, CURLOPT_AUTOREFERER, 1L); - curl_easy_setopt(ch, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, NULL); - curl_easy_setopt(ch, CURLOPT_DEBUGFUNCTION, http_curl_raw_callback); - curl_easy_setopt(ch, CURLOPT_READFUNCTION, http_curl_read_callback); - curl_easy_setopt(ch, CURLOPT_IOCTLFUNCTION, http_curl_ioctl_callback); - curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, http_curl_dummy_callback); - - /* set context */ - if (request) { - curl_easy_setopt(ch, CURLOPT_DEBUGDATA, request); - - /* attach curl handle */ - request->ch = ch; - /* set defaults (also in http_request_reset()) */ - http_request_defaults(request); - } - } - - return ch; -} -/* }}} */ - -/* {{{ CURL *http_curl_copy(CURL *) */ -PHP_HTTP_API CURL *_http_curl_copy(CURL *ch TSRMLS_DC) -{ - CURL *copy; - - if (SUCCESS == http_persistent_handle_accrete("http_request", ch, ©)) { - return copy; - } - return NULL; -} -/* }}} */ - -/* {{{ void http_curl_free(CURL **) */ -PHP_HTTP_API void _http_curl_free(CURL **ch TSRMLS_DC) -{ - if (*ch) { - curl_easy_setopt(*ch, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(*ch, CURLOPT_PROGRESSFUNCTION, NULL); - curl_easy_setopt(*ch, CURLOPT_VERBOSE, 0L); - curl_easy_setopt(*ch, CURLOPT_DEBUGFUNCTION, NULL); - - http_persistent_handle_release("http_request", ch); - } -} -/* }}} */ - -/* {{{ http_request *http_request_init(http_request *) */ -PHP_HTTP_API http_request *_http_request_init_ex(http_request *request, CURL *ch, http_request_method meth, const char *url ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - http_request *r; - - if (request) { - r = request; - } else { - r = emalloc_rel(sizeof(http_request)); - } - memset(r, 0, sizeof(http_request)); - - r->ch = ch; - r->url = (url) ? http_absolute_url(url) : NULL; - r->meth = (meth > 0) ? meth : HTTP_GET; - - phpstr_init(&r->conv.request); - phpstr_init_ex(&r->conv.response, HTTP_CURLBUF_SIZE, 0); - phpstr_init(&r->_cache.cookies); - zend_hash_init(&r->_cache.options, 0, NULL, ZVAL_PTR_DTOR, 0); - - TSRMLS_SET_CTX(r->tsrm_ls); - - return r; -} -/* }}} */ - -/* {{{ void http_request_dtor(http_request *) */ -PHP_HTTP_API void _http_request_dtor(http_request *request) -{ - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - - http_request_reset(request); - http_curl_free(&request->ch); - - phpstr_dtor(&request->_cache.cookies); - zend_hash_destroy(&request->_cache.options); - if (request->_cache.headers) { - curl_slist_free_all(request->_cache.headers); - request->_cache.headers = NULL; - } - if (request->_progress_callback) { - zval_ptr_dtor(&request->_progress_callback); - request->_progress_callback = NULL; - } -} -/* }}} */ - -/* {{{ void http_request_free(http_request **) */ -PHP_HTTP_API void _http_request_free(http_request **request) -{ - if (*request) { - TSRMLS_FETCH_FROM_CTX((*request)->tsrm_ls); - http_request_body_free(&(*request)->body); - http_request_dtor(*request); - efree(*request); - *request = NULL; - } -} -/* }}} */ - -/* {{{ void http_request_reset(http_request *) */ -PHP_HTTP_API void _http_request_reset(http_request *request) -{ - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - STR_SET(request->url, NULL); - request->conv.last_type = 0; - phpstr_dtor(&request->conv.request); - phpstr_dtor(&request->conv.response); - http_request_body_dtor(request->body); - http_request_defaults(request); - - if (request->ch) { - http_request_storage *st = http_request_storage_get(request->ch); - - if (st) { - if (st->url) { - pefree(st->url, 1); - st->url = NULL; - } - if (st->cookiestore) { - pefree(st->cookiestore, 1); - st->cookiestore = NULL; - } - st->errorbuffer[0] = '\0'; - } - } -} -/* }}} */ - -/* {{{ STATUS http_request_enable_cookies(http_request *) */ -PHP_HTTP_API STATUS _http_request_enable_cookies(http_request *request) -{ - int initialized = 1; - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - - HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0); - if (initialized && (http_request_cookies_enabled(request) || (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIEFILE, "")))) { - return SUCCESS; - } - http_error(HE_WARNING, HTTP_E_REQUEST, "Could not enable cookies for this session"); - return FAILURE; -} -/* }}} */ - -/* {{{ STATUS http_request_reset_cookies(http_request *, int) */ -PHP_HTTP_API STATUS _http_request_reset_cookies(http_request *request, int session_only) -{ - int initialized = 1; - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - - HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0); - if (initialized) { - if (!http_request_cookies_enabled(request)) { - if (SUCCESS != http_request_enable_cookies(request)) { - return FAILURE; - } - } - if (session_only) { -#if HTTP_CURL_VERSION(7,15,4) - if (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "SESS")) { - return SUCCESS; - } -#else - http_error(HE_WARNING, HTTP_E_REQUEST, "Could not reset session cookies (need libcurl >= v7.15.4)"); -#endif - } else { -#if HTTP_CURL_VERSION(7,14,1) - if (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "ALL")) { - return SUCCESS; - } -#else - http_error(HE_WARNING, HTTP_E_REQUEST, "Could not reset cookies (need libcurl >= v7.14.1)"); -#endif - } - } - return FAILURE; -} -/* }}} */ - -PHP_HTTP_API STATUS _http_request_flush_cookies(http_request *request) -{ - int initialized = 1; - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - - HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0); - if (initialized) { - if (!http_request_cookies_enabled(request)) { - return FAILURE; - } -#if HTTP_CURL_VERSION(7,17,1) - if (CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "FLUSH")) { - return SUCCESS; - } -#else - http_error(HE_WARNING, HTTP_E_REQUEST, "Could not flush cookies (need libcurl >= v7.17.1)"); -#endif - } - return FAILURE; -} - -/* {{{ void http_request_defaults(http_request *) */ -PHP_HTTP_API void _http_request_defaults(http_request *request) -{ - if (request->ch) { - HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, NULL); - HTTP_CURL_OPT(CURLOPT_URL, NULL); - HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 1L); -#if HTTP_CURL_VERSION(7,19,4) - HTTP_CURL_OPT(CURLOPT_NOPROXY, NULL); -#endif - HTTP_CURL_OPT(CURLOPT_PROXY, NULL); - HTTP_CURL_OPT(CURLOPT_PROXYPORT, 0L); - HTTP_CURL_OPT(CURLOPT_PROXYTYPE, 0L); - /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */ -#if HTTP_CURL_VERSION(7,19,1) - HTTP_CURL_OPT(CURLOPT_PROXYUSERNAME, NULL); - HTTP_CURL_OPT(CURLOPT_PROXYPASSWORD, NULL); -#endif - HTTP_CURL_OPT(CURLOPT_PROXYAUTH, 0L); - HTTP_CURL_OPT(CURLOPT_HTTPPROXYTUNNEL, 0L); - HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT, 60L); - HTTP_CURL_OPT(CURLOPT_IPRESOLVE, 0); - HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT, 0L); - HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME, 0L); -#if HTTP_CURL_VERSION(7,15,5) - /* LFS weirdance - HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) 0); - HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) 0); - */ -#endif - /* crashes - HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, 5L); */ - HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT, 0L); - HTTP_CURL_OPT(CURLOPT_FORBID_REUSE, 0L); - HTTP_CURL_OPT(CURLOPT_INTERFACE, NULL); - HTTP_CURL_OPT(CURLOPT_PORT, 0L); -#if HTTP_CURL_VERSION(7,19,0) - HTTP_CURL_OPT(CURLOPT_ADDRESS_SCOPE, 0L); -#endif -#if HTTP_CURL_VERSION(7,15,2) - HTTP_CURL_OPT(CURLOPT_LOCALPORT, 0L); - HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE, 0L); -#endif - /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */ -#if HTTP_CURL_VERSION(7,19,1) - HTTP_CURL_OPT(CURLOPT_USERNAME, NULL); - HTTP_CURL_OPT(CURLOPT_PASSWORD, NULL); -#endif - HTTP_CURL_OPT(CURLOPT_HTTPAUTH, 0L); - HTTP_CURL_OPT(CURLOPT_ENCODING, NULL); -#if HTTP_CURL_VERSION(7,16,2) - /* we do this ourself anyway */ - HTTP_CURL_OPT(CURLOPT_HTTP_CONTENT_DECODING, 0L); - HTTP_CURL_OPT(CURLOPT_HTTP_TRANSFER_DECODING, 0L); -#endif - HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION, 0L); -#if HTTP_CURL_VERSION(7,19,1) - HTTP_CURL_OPT(CURLOPT_POSTREDIR, 0L); -#elif HTTP_CURL_VERSION(7,17,1) - HTTP_CURL_OPT(CURLOPT_POST301, 0L); -#endif - HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH, 0L); - HTTP_CURL_OPT(CURLOPT_REFERER, NULL); - HTTP_CURL_OPT(CURLOPT_USERAGENT, "PECL::HTTP/" PHP_HTTP_VERSION " (PHP/" PHP_VERSION ")"); - HTTP_CURL_OPT(CURLOPT_HTTPHEADER, NULL); - HTTP_CURL_OPT(CURLOPT_COOKIE, NULL); - HTTP_CURL_OPT(CURLOPT_COOKIESESSION, 0L); - /* these options would enable curl's cookie engine by default which we don't want - HTTP_CURL_OPT(CURLOPT_COOKIEFILE, NULL); - HTTP_CURL_OPT(CURLOPT_COOKIEJAR, NULL); */ -#if HTTP_CURL_VERSION(7,14,1) - HTTP_CURL_OPT(CURLOPT_COOKIELIST, NULL); -#endif - HTTP_CURL_OPT(CURLOPT_RANGE, NULL); - HTTP_CURL_OPT(CURLOPT_RESUME_FROM, 0L); - HTTP_CURL_OPT(CURLOPT_MAXFILESIZE, 0L); - HTTP_CURL_OPT(CURLOPT_TIMECONDITION, 0L); - HTTP_CURL_OPT(CURLOPT_TIMEVALUE, 0L); - HTTP_CURL_OPT(CURLOPT_TIMEOUT, 0L); - HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT, 3); - HTTP_CURL_OPT(CURLOPT_SSLCERT, NULL); - HTTP_CURL_OPT(CURLOPT_SSLCERTTYPE, NULL); - HTTP_CURL_OPT(CURLOPT_SSLCERTPASSWD, NULL); - HTTP_CURL_OPT(CURLOPT_SSLKEY, NULL); - HTTP_CURL_OPT(CURLOPT_SSLKEYTYPE, NULL); - HTTP_CURL_OPT(CURLOPT_SSLKEYPASSWD, NULL); - HTTP_CURL_OPT(CURLOPT_SSLENGINE, NULL); - HTTP_CURL_OPT(CURLOPT_SSLVERSION, 0L); - HTTP_CURL_OPT(CURLOPT_SSL_VERIFYPEER, 0L); - HTTP_CURL_OPT(CURLOPT_SSL_VERIFYHOST, 0L); - HTTP_CURL_OPT(CURLOPT_SSL_CIPHER_LIST, NULL); -#if HTTP_CURL_VERSION(7,19,0) - HTTP_CURL_OPT(CURLOPT_ISSUERCERT, NULL); - #if defined(HTTP_HAVE_OPENSSL) - HTTP_CURL_OPT(CURLOPT_CRLFILE, NULL); - #endif -#endif -#if HTTP_CURL_VERSION(7,19,1) && defined(HTTP_HAVE_OPENSSL) - HTTP_CURL_OPT(CURLOPT_CERTINFO, NULL); -#endif -#ifdef HTTP_CURL_CAINFO - HTTP_CURL_OPT(CURLOPT_CAINFO, HTTP_CURL_CAINFO); -#else - HTTP_CURL_OPT(CURLOPT_CAINFO, NULL); -#endif - HTTP_CURL_OPT(CURLOPT_CAPATH, NULL); - HTTP_CURL_OPT(CURLOPT_RANDOM_FILE, NULL); - HTTP_CURL_OPT(CURLOPT_EGDSOCKET, NULL); - HTTP_CURL_OPT(CURLOPT_POSTFIELDS, NULL); - HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE, 0L); - HTTP_CURL_OPT(CURLOPT_HTTPPOST, NULL); - HTTP_CURL_OPT(CURLOPT_IOCTLDATA, NULL); - HTTP_CURL_OPT(CURLOPT_READDATA, NULL); - HTTP_CURL_OPT(CURLOPT_INFILESIZE, 0L); - HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE); - HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST, NULL); - HTTP_CURL_OPT(CURLOPT_NOBODY, 0L); - HTTP_CURL_OPT(CURLOPT_POST, 0L); - HTTP_CURL_OPT(CURLOPT_UPLOAD, 0L); - HTTP_CURL_OPT(CURLOPT_HTTPGET, 1L); - } -} -/* }}} */ - -PHP_HTTP_API void _http_request_set_progress_callback(http_request *request, zval *cb) -{ - if (request->_progress_callback) { - zval_ptr_dtor(&request->_progress_callback); - } - if ((request->_progress_callback = cb)) { - ZVAL_ADDREF(cb); - HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 0); - HTTP_CURL_OPT(CURLOPT_PROGRESSDATA, request); - HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, http_curl_progress_callback); - } else { - HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 1); - HTTP_CURL_OPT(CURLOPT_PROGRESSDATA, NULL); - HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, NULL); - } -} - -/* {{{ STATUS http_request_prepare(http_request *, HashTable *) */ -PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *options) -{ - zval *zoption; - zend_bool range_req = 0; - http_request_storage *storage; - - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - - HTTP_CHECK_CURL_INIT(request->ch, http_curl_init(request), return FAILURE); - - if (!request->url) { - return FAILURE; - } - if (!(storage = http_request_storage_get(request->ch))) { - return FAILURE; - } - storage->errorbuffer[0] = '\0'; - /* set options */ - if (storage->url) { - pefree(storage->url, 1); - } - storage->url = pestrdup(request->url, 1); - HTTP_CURL_OPT(CURLOPT_URL, storage->url); - - /* progress callback */ - if ((zoption = http_request_option(request, options, "onprogress", -1))) { - http_request_set_progress_callback(request, zoption); - } - - /* proxy */ - if ((zoption = http_request_option(request, options, "proxyhost", IS_STRING))) { - HTTP_CURL_OPT(CURLOPT_PROXY, Z_STRVAL_P(zoption)); - /* type */ - if ((zoption = http_request_option(request, options, "proxytype", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_PROXYTYPE, Z_LVAL_P(zoption)); - } - /* port */ - if ((zoption = http_request_option(request, options, "proxyport", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_PROXYPORT, Z_LVAL_P(zoption)); - } - /* user:pass */ - if ((zoption = http_request_option(request, options, "proxyauth", IS_STRING)) && Z_STRLEN_P(zoption)) { - HTTP_CURL_OPT(CURLOPT_PROXYUSERPWD, Z_STRVAL_P(zoption)); - } - /* auth method */ - if ((zoption = http_request_option(request, options, "proxyauthtype", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_PROXYAUTH, Z_LVAL_P(zoption)); - } - /* tunnel */ - if ((zoption = http_request_option(request, options, "proxytunnel", IS_BOOL)) && Z_BVAL_P(zoption)) { - HTTP_CURL_OPT(CURLOPT_HTTPPROXYTUNNEL, 1L); - } - } -#if HTTP_CURL_VERSION(7,19,4) - if ((zoption = http_request_option(request, options, "noproxy", IS_STRING))) { - HTTP_CURL_OPT(CURLOPT_NOPROXY, Z_STRVAL_P(zoption)); - } -#endif - - /* dns */ - if ((zoption = http_request_option(request, options, "dns_cache_timeout", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT, Z_LVAL_P(zoption)); - } - if ((zoption = http_request_option(request, options, "ipresolve", IS_LONG)) && Z_LVAL_P(zoption)) { - HTTP_CURL_OPT(CURLOPT_IPRESOLVE, Z_LVAL_P(zoption)); - } - - /* limits */ - if ((zoption = http_request_option(request, options, "low_speed_limit", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT, Z_LVAL_P(zoption)); - } - if ((zoption = http_request_option(request, options, "low_speed_time", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME, Z_LVAL_P(zoption)); - } -#if HTTP_CURL_VERSION(7,15,5) - /* LSF weirdance - if ((zoption = http_request_option(request, options, "max_send_speed", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption)); - } - if ((zoption = http_request_option(request, options, "max_recv_speed", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption)); - } - */ -#endif - /* crashes - if ((zoption = http_request_option(request, options, "maxconnects", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, Z_LVAL_P(zoption)); - } */ - if ((zoption = http_request_option(request, options, "fresh_connect", IS_BOOL)) && Z_BVAL_P(zoption)) { - HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT, 1L); - } - if ((zoption = http_request_option(request, options, "forbid_reuse", IS_BOOL)) && Z_BVAL_P(zoption)) { - HTTP_CURL_OPT(CURLOPT_FORBID_REUSE, 1L); - } - - /* outgoing interface */ - if ((zoption = http_request_option(request, options, "interface", IS_STRING))) { - HTTP_CURL_OPT(CURLOPT_INTERFACE, Z_STRVAL_P(zoption)); - -#if HTTP_CURL_VERSION(7,15,2) - if ((zoption = http_request_option(request, options, "portrange", IS_ARRAY))) { - zval **prs, **pre; - - zend_hash_internal_pointer_reset(Z_ARRVAL_P(zoption)); - if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void *) &prs)) { - zend_hash_move_forward(Z_ARRVAL_P(zoption)); - if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void *) &pre)) { - zval *prs_cpy = http_zsep(IS_LONG, *prs); - zval *pre_cpy = http_zsep(IS_LONG, *pre); - - if (Z_LVAL_P(prs_cpy) && Z_LVAL_P(pre_cpy)) { - HTTP_CURL_OPT(CURLOPT_LOCALPORT, MIN(Z_LVAL_P(prs_cpy), Z_LVAL_P(pre_cpy))); - HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE, labs(Z_LVAL_P(prs_cpy)-Z_LVAL_P(pre_cpy))+1L); - } - zval_ptr_dtor(&prs_cpy); - zval_ptr_dtor(&pre_cpy); - } - } - } -#endif - } - - /* another port */ - if ((zoption = http_request_option(request, options, "port", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_PORT, Z_LVAL_P(zoption)); - } - - /* RFC4007 zone_id */ -#if HTTP_CURL_VERSION(7,19,0) - if ((zoption = http_request_option(request, options, "address_scope", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_ADDRESS_SCOPE, Z_LVAL_P(zoption)); - } -#endif - - /* auth */ - if ((zoption = http_request_option(request, options, "httpauth", IS_STRING)) && Z_STRLEN_P(zoption)) { - HTTP_CURL_OPT(CURLOPT_USERPWD, Z_STRVAL_P(zoption)); - } - if ((zoption = http_request_option(request, options, "httpauthtype", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_HTTPAUTH, Z_LVAL_P(zoption)); - } - - /* redirects, defaults to 0 */ - if ((zoption = http_request_option(request, options, "redirect", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION, Z_LVAL_P(zoption) ? 1L : 0L); - HTTP_CURL_OPT(CURLOPT_MAXREDIRS, Z_LVAL_P(zoption)); - if ((zoption = http_request_option(request, options, "unrestrictedauth", IS_BOOL))) { - HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH, Z_LVAL_P(zoption)); - } -#if HTTP_CURL_VERSION(7,17,1) - if ((zoption = http_request_option(request, options, "postredir", IS_BOOL))) { -# if HTTP_CURL_VERSION(7,19,1) - HTTP_CURL_OPT(CURLOPT_POSTREDIR, Z_BVAL_P(zoption) ? 1L : 0L); -# else - HTTP_CURL_OPT(CURLOPT_POST301, Z_BVAL_P(zoption) ? 1L : 0L); -# endif - } -#endif - } - - /* retries, defaults to 0 */ - if ((zoption = http_request_option(request, options, "retrycount", IS_LONG))) { - request->_retry.count = Z_LVAL_P(zoption); - if ((zoption = http_request_option(request, options, "retrydelay", IS_DOUBLE))) { - request->_retry.delay = Z_DVAL_P(zoption); - } else { - request->_retry.delay = 0; - } - } else { - request->_retry.count = 0; - } - - /* referer */ - if ((zoption = http_request_option(request, options, "referer", IS_STRING)) && Z_STRLEN_P(zoption)) { - HTTP_CURL_OPT(CURLOPT_REFERER, Z_STRVAL_P(zoption)); - } - - /* useragent, default "PECL::HTTP/version (PHP/version)" */ - if ((zoption = http_request_option(request, options, "useragent", IS_STRING))) { - /* allow to send no user agent, not even default one */ - if (Z_STRLEN_P(zoption)) { - HTTP_CURL_OPT(CURLOPT_USERAGENT, Z_STRVAL_P(zoption)); - } else { - HTTP_CURL_OPT(CURLOPT_USERAGENT, NULL); - } - } - - /* resume */ - if ((zoption = http_request_option(request, options, "resume", IS_LONG)) && (Z_LVAL_P(zoption) > 0)) { - range_req = 1; - HTTP_CURL_OPT(CURLOPT_RESUME_FROM, Z_LVAL_P(zoption)); - } - /* or range of kind array(array(0,499), array(100,1499)) */ - else if ((zoption = http_request_option(request, options, "range", IS_ARRAY)) && zend_hash_num_elements(Z_ARRVAL_P(zoption))) { - HashPosition pos1, pos2; - zval **rr, **rb, **re; - phpstr rs; - - phpstr_init(&rs); - FOREACH_VAL(pos1, zoption, rr) { - if (Z_TYPE_PP(rr) == IS_ARRAY) { - zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(rr), &pos2); - if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr), (void *) &rb, &pos2)) { - zend_hash_move_forward_ex(Z_ARRVAL_PP(rr), &pos2); - if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr), (void *) &re, &pos2)) { - if ( ((Z_TYPE_PP(rb) == IS_LONG) || ((Z_TYPE_PP(rb) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(rb), Z_STRLEN_PP(rb), NULL, NULL, 1))) && - ((Z_TYPE_PP(re) == IS_LONG) || ((Z_TYPE_PP(re) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(re), Z_STRLEN_PP(re), NULL, NULL, 1)))) { - zval *rbl = http_zsep(IS_LONG, *rb); - zval *rel = http_zsep(IS_LONG, *re); - - if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) { - phpstr_appendf(&rs, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel)); - } - zval_ptr_dtor(&rbl); - zval_ptr_dtor(&rel); - } - } - } - } - } - - if (PHPSTR_LEN(&rs)) { - zval *cached_range; - - /* ditch last comma */ - PHPSTR_VAL(&rs)[PHPSTR_LEN(&rs)-- -1] = '\0'; - /* cache string */ - MAKE_STD_ZVAL(cached_range); - ZVAL_STRINGL(cached_range, PHPSTR_VAL(&rs), PHPSTR_LEN(&rs), 0); - HTTP_CURL_OPT(CURLOPT_RANGE, Z_STRVAL_P(http_request_option_cache(request, "range", cached_range))); - zval_ptr_dtor(&cached_range); - } - } - - /* additional headers, array('name' => 'value') */ - if (request->_cache.headers) { - curl_slist_free_all(request->_cache.headers); - request->_cache.headers = NULL; - } - if ((zoption = http_request_option(request, options, "headers", IS_ARRAY))) { - HashKey header_key = initHashKey(0); - zval **header_val; - HashPosition pos; - phpstr header; - - phpstr_init(&header); - FOREACH_KEYVAL(pos, zoption, header_key, header_val) { - if (header_key.type == HASH_KEY_IS_STRING) { - zval *header_cpy = http_zsep(IS_STRING, *header_val); - - if (!strcasecmp(header_key.str, "range")) { - range_req = 1; - } - - phpstr_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy)); - phpstr_fix(&header); - request->_cache.headers = curl_slist_append(request->_cache.headers, PHPSTR_VAL(&header)); - phpstr_reset(&header); - - zval_ptr_dtor(&header_cpy); - } - } - phpstr_dtor(&header); - } - /* etag */ - if ((zoption = http_request_option(request, options, "etag", IS_STRING)) && Z_STRLEN_P(zoption)) { - zend_bool is_quoted; - phpstr header; - - phpstr_init(&header); - phpstr_appendf(&header, "%s: ", range_req?"If-Match":"If-None-Match"); - if ((Z_STRVAL_P(zoption)[0] == '"') && (Z_STRVAL_P(zoption)[Z_STRLEN_P(zoption)-1] == '"')) { - /* properly quoted etag */ - phpstr_append(&header, Z_STRVAL_P(zoption), Z_STRLEN_P(zoption)); - } else if ((Z_STRVAL_P(zoption)[0] == 'W') && (Z_STRVAL_P(zoption)[1] == '/')) { - /* weak etag */ - if ((Z_STRLEN_P(zoption) > 3) && (Z_STRVAL_P(zoption)[2] == '"') && (Z_STRVAL_P(zoption)[Z_STRLEN_P(zoption)-1] == '"')) { - /* quoted */ - phpstr_append(&header, Z_STRVAL_P(zoption), Z_STRLEN_P(zoption)); - } else { - /* unquoted */ - phpstr_appendf(&header, "W/\"%s\"", Z_STRVAL_P(zoption) + 2); - } - } else { - /* assume unquoted etag */ - phpstr_appendf(&header, "\"%s\"", Z_STRVAL_P(zoption)); - } - phpstr_fix(&header); - - request->_cache.headers = curl_slist_append(request->_cache.headers, PHPSTR_VAL(&header)); - phpstr_dtor(&header); - } - /* compression */ - if ((zoption = http_request_option(request, options, "compress", IS_BOOL)) && Z_LVAL_P(zoption)) { - request->_cache.headers = curl_slist_append(request->_cache.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5"); - } - HTTP_CURL_OPT(CURLOPT_HTTPHEADER, request->_cache.headers); - - /* lastmodified */ - if ((zoption = http_request_option(request, options, "lastmodified", IS_LONG))) { - if (Z_LVAL_P(zoption)) { - if (Z_LVAL_P(zoption) > 0) { - HTTP_CURL_OPT(CURLOPT_TIMEVALUE, Z_LVAL_P(zoption)); - } else { - HTTP_CURL_OPT(CURLOPT_TIMEVALUE, (long) HTTP_G->request.time + Z_LVAL_P(zoption)); - } - HTTP_CURL_OPT(CURLOPT_TIMECONDITION, (long) (range_req ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE)); - } else { - HTTP_CURL_OPT(CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE); - } - } - - /* cookies, array('name' => 'value') */ - if ((zoption = http_request_option(request, options, "cookies", IS_ARRAY))) { - phpstr_dtor(&request->_cache.cookies); - if (zend_hash_num_elements(Z_ARRVAL_P(zoption))) { - zval *urlenc_cookies = NULL; - /* check whether cookies should not be urlencoded; default is to urlencode them */ - if ((!(urlenc_cookies = http_request_option(request, options, "encodecookies", IS_BOOL))) || Z_BVAL_P(urlenc_cookies)) { - if (SUCCESS == http_urlencode_hash_recursive(HASH_OF(zoption), &request->_cache.cookies, "; ", lenof("; "), NULL, 0)) { - phpstr_fix(&request->_cache.cookies); - HTTP_CURL_OPT(CURLOPT_COOKIE, request->_cache.cookies.data); - } - } else { - HashPosition pos; - HashKey cookie_key = initHashKey(0); - zval **cookie_val; - - FOREACH_KEYVAL(pos, zoption, cookie_key, cookie_val) { - if (cookie_key.type == HASH_KEY_IS_STRING) { - zval *val = http_zsep(IS_STRING, *cookie_val); - phpstr_appendf(&request->_cache.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(val)); - zval_ptr_dtor(&val); - } - } - - phpstr_fix(&request->_cache.cookies); - if (PHPSTR_LEN(&request->_cache.cookies)) { - HTTP_CURL_OPT(CURLOPT_COOKIE, PHPSTR_VAL(&request->_cache.cookies)); - } - } - } - } - - /* don't load session cookies from cookiestore */ - if ((zoption = http_request_option(request, options, "cookiesession", IS_BOOL)) && Z_BVAL_P(zoption)) { - HTTP_CURL_OPT(CURLOPT_COOKIESESSION, 1L); - } - - /* cookiestore, read initial cookies from that file and store cookies back into that file */ - if ((zoption = http_request_option(request, options, "cookiestore", IS_STRING))) { - if (Z_STRLEN_P(zoption)) { - HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(zoption), return FAILURE); - } - if (storage->cookiestore) { - pefree(storage->cookiestore, 1); - } - storage->cookiestore = pestrndup(Z_STRVAL_P(zoption), Z_STRLEN_P(zoption), 1); - HTTP_CURL_OPT(CURLOPT_COOKIEFILE, storage->cookiestore); - HTTP_CURL_OPT(CURLOPT_COOKIEJAR, storage->cookiestore); - } - - /* maxfilesize */ - if ((zoption = http_request_option(request, options, "maxfilesize", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_MAXFILESIZE, Z_LVAL_P(zoption)); - } - - /* http protocol */ - if ((zoption = http_request_option(request, options, "protocol", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, Z_LVAL_P(zoption)); - } - -#if HTTP_CURL_VERSION(7,16,2) - /* timeout, defaults to 0 */ - if ((zoption = http_request_option(request, options, "timeout", IS_DOUBLE))) { - HTTP_CURL_OPT(CURLOPT_TIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000)); - } - /* connecttimeout, defaults to 0 */ - if ((zoption = http_request_option(request, options, "connecttimeout", IS_DOUBLE))) { - HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000)); - } -#else - /* timeout, defaults to 0 */ - if ((zoption = http_request_option(request, options, "timeout", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_TIMEOUT, Z_LVAL_P(zoption)); - } - /* connecttimeout, defaults to 0 */ - if ((zoption = http_request_option(request, options, "connecttimeout", IS_LONG))) { - HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT, Z_LVAL_P(zoption)); - } -#endif - - /* ssl */ - if ((zoption = http_request_option(request, options, "ssl", IS_ARRAY))) { - HashKey key = initHashKey(0); - zval **param; - HashPosition pos; - - FOREACH_KEYVAL(pos, zoption, key, param) { - if (key.type == HASH_KEY_IS_STRING) { - HTTP_CURL_OPT_STRING(CURLOPT_SSLCERT, 0, 1); - HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTTYPE, 0, 0); - HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTPASSWD, 0, 0); - - HTTP_CURL_OPT_STRING(CURLOPT_SSLKEY, 0, 0); - HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYTYPE, 0, 0); - HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYPASSWD, 0, 0); - - HTTP_CURL_OPT_STRING(CURLOPT_SSLENGINE, 0, 0); - HTTP_CURL_OPT_LONG(CURLOPT_SSLVERSION, 0); - - HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYPEER, 1); - HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYHOST, 1); - HTTP_CURL_OPT_STRING(CURLOPT_SSL_CIPHER_LIST, 1, 0); - - HTTP_CURL_OPT_STRING(CURLOPT_CAINFO, -3, 1); - HTTP_CURL_OPT_STRING(CURLOPT_CAPATH, -3, 1); - HTTP_CURL_OPT_STRING(CURLOPT_RANDOM_FILE, -3, 1); - HTTP_CURL_OPT_STRING(CURLOPT_EGDSOCKET, -3, 1); -#if HTTP_CURL_VERSION(7,19,0) - HTTP_CURL_OPT_STRING(CURLOPT_ISSUERCERT, -3, 1); - #if defined(HTTP_HAVE_OPENSSL) - HTTP_CURL_OPT_STRING(CURLOPT_CRLFILE, -3, 1); - #endif -#endif -#if HTTP_CURL_VERSION(7,19,1) && defined(HTTP_HAVE_OPENSSL) - HTTP_CURL_OPT_LONG(CURLOPT_CERTINFO, -3); -#endif - } - } - } - - /* request method */ - switch (request->meth) { - case HTTP_GET: - HTTP_CURL_OPT(CURLOPT_HTTPGET, 1L); - break; - - case HTTP_HEAD: - HTTP_CURL_OPT(CURLOPT_NOBODY, 1L); - break; - - case HTTP_POST: - HTTP_CURL_OPT(CURLOPT_POST, 1L); - break; - - case HTTP_PUT: - HTTP_CURL_OPT(CURLOPT_UPLOAD, 1L); - break; - - default: - if (http_request_method_exists(0, request->meth, NULL)) { - HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST, http_request_method_name(request->meth)); - } else { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Unsupported request method: %d (%s)", request->meth, request->url); - return FAILURE; - } - break; - } - - /* attach request body */ - if (request->body && (request->meth != HTTP_GET) && (request->meth != HTTP_HEAD) && (request->meth != HTTP_OPTIONS)) { - switch (request->body->type) { - case HTTP_REQUEST_BODY_EMPTY: - /* nothing */ - break; - - case HTTP_REQUEST_BODY_CURLPOST: - HTTP_CURL_OPT(CURLOPT_HTTPPOST, (struct curl_httppost *) request->body->data); - break; - - case HTTP_REQUEST_BODY_CSTRING: - if (request->meth != HTTP_PUT) { - HTTP_CURL_OPT(CURLOPT_POSTFIELDS, request->body->data); - HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE, request->body->size); - break; - } - /* fallthrough, PUT/UPLOAD _needs_ READDATA */ - case HTTP_REQUEST_BODY_UPLOADFILE: - HTTP_CURL_OPT(CURLOPT_IOCTLDATA, request); - HTTP_CURL_OPT(CURLOPT_READDATA, request); - HTTP_CURL_OPT(CURLOPT_INFILESIZE, request->body->size); - break; - - default: - /* shouldn't ever happen */ - http_error_ex(HE_ERROR, 0, "Unknown request body type: %d (%s)", request->body->type, request->url); - return FAILURE; - } - } - - return SUCCESS; -} -/* }}} */ - -/* {{{ void http_request_exec(http_request *) */ -PHP_HTTP_API void _http_request_exec(http_request *request) -{ - uint tries = 0; - CURLcode result; - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - -retry: - if (CURLE_OK != (result = curl_easy_perform(request->ch))) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST, "%s; %s (%s)", curl_easy_strerror(result), http_request_storage_get(request->ch)->errorbuffer, request->url); -#ifdef ZEND_ENGINE_2 - if ((HTTP_G->only_exceptions || GLOBAL_ERROR_HANDLING == EH_THROW) && EG(exception)) { - add_property_long(EG(exception), "curlCode", result); - } -#endif - - if (request->_retry.count > tries++) { - switch (result) { - case CURLE_COULDNT_RESOLVE_PROXY: - case CURLE_COULDNT_RESOLVE_HOST: - case CURLE_COULDNT_CONNECT: - case CURLE_WRITE_ERROR: - case CURLE_READ_ERROR: - case CURLE_OPERATION_TIMEDOUT: - case CURLE_SSL_CONNECT_ERROR: - case CURLE_GOT_NOTHING: - case CURLE_SSL_ENGINE_SETFAILED: - case CURLE_SEND_ERROR: - case CURLE_RECV_ERROR: - case CURLE_SSL_ENGINE_INITFAILED: - case CURLE_LOGIN_DENIED: - if (request->_retry.delay >= HTTP_DIFFSEC) { - http_sleep(request->_retry.delay); - } - goto retry; - default: - break; - } - } - } -} -/* }}} */ - -/* {{{ static size_t http_curl_read_callback(void *, size_t, size_t, void *) */ -static size_t http_curl_read_callback(void *data, size_t len, size_t n, void *ctx) -{ - http_request *request = (http_request *) ctx; - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - - if (request->body) { - switch (request->body->type) { - case HTTP_REQUEST_BODY_CSTRING: - { - size_t out = MIN(len * n, request->body->size - request->body->priv); - - if (out) { - memcpy(data, ((char *) request->body->data) + request->body->priv, out); - request->body->priv += out; - return out; - } - break; - } - - case HTTP_REQUEST_BODY_UPLOADFILE: - return php_stream_read((php_stream *) request->body->data, data, len * n); - } - } - return 0; -} -/* }}} */ - -/* {{{ static int http_curl_progress_callback(void *, double, double, double, double) */ -static int http_curl_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow) -{ - zval *param, retval; - http_request *request = (http_request *) ctx; - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - - INIT_PZVAL(&retval); - ZVAL_NULL(&retval); - - MAKE_STD_ZVAL(param); - array_init(param); - add_assoc_double(param, "dltotal", dltotal); - add_assoc_double(param, "dlnow", dlnow); - add_assoc_double(param, "ultotal", ultotal); - add_assoc_double(param, "ulnow", ulnow); - - with_error_handling(EH_NORMAL, NULL) { - request->_in_progress_cb = 1; - call_user_function(EG(function_table), NULL, request->_progress_callback, &retval, 1, ¶m TSRMLS_CC); - request->_in_progress_cb = 0; - } end_error_handling(); - - zval_ptr_dtor(¶m); - zval_dtor(&retval); - - return 0; -} -/* }}} */ - -/* {{{ static curlioerr http_curl_ioctl_callback(CURL *, curliocmd, void *) */ -static curlioerr http_curl_ioctl_callback(CURL *ch, curliocmd cmd, void *ctx) -{ - http_request *request = (http_request *) ctx; - TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); - - if (cmd != CURLIOCMD_RESTARTREAD) { - return CURLIOE_UNKNOWNCMD; - } - - if (request->body) { - switch (request->body->type) { - case HTTP_REQUEST_BODY_CSTRING: - request->body->priv = 0; - return CURLIOE_OK; - break; - - case HTTP_REQUEST_BODY_UPLOADFILE: - if (SUCCESS == php_stream_rewind((php_stream *) request->body->data)) { - return CURLIOE_OK; - } - break; - } - } - - return CURLIOE_FAILRESTART; -} -/* }}} */ - -/* {{{ static int http_curl_raw_callback(CURL *, curl_infotype, char *, size_t, void *) */ -static int http_curl_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx) -{ - http_request *request = (http_request *) ctx; - -#define EMPTY_HEADER(d, l) (!l || (l == 1 && d[0] == '\n') || (l == 2 && d[0] == '\r' && d[1] == '\n')) - switch (type) { - case CURLINFO_DATA_IN: - if (request->conv.last_type == CURLINFO_HEADER_IN) { - phpstr_appends(&request->conv.response, HTTP_CRLF); - } - phpstr_append(&request->conv.response, data, length); - break; - case CURLINFO_HEADER_IN: - if (!EMPTY_HEADER(data, length)) { - phpstr_append(&request->conv.response, data, length); - } - break; - case CURLINFO_DATA_OUT: - case CURLINFO_HEADER_OUT: - phpstr_append(&request->conv.request, data, length); - break; - default: - break; - } - -#if 0 - { - const char _sym[] = "><><><"; - if (type) { - for (fprintf(stderr, "%c ", _sym[type-1]); length--; data++) { - fprintf(stderr, HTTP_IS_CTYPE(print, *data)?"%c":"\\x%02X", (int) *data); - if (*data == '\n' && length) { - fprintf(stderr, "\n%c ", _sym[type-1]); - } - } - fprintf(stderr, "\n"); - } else { - fprintf(stderr, "# %s", data); - } - } -#endif - - if (type) { - request->conv.last_type = type; - } - return 0; -} -/* }}} */ - -/* {{{ static inline zval *http_request_option(http_request *, HashTable *, char *, size_t, int) */ -static inline zval *_http_request_option_ex(http_request *r, HashTable *options, char *key, size_t keylen, int type TSRMLS_DC) -{ - if (options) { - zval **zoption; - ulong h = zend_hash_func(key, keylen); - - if (SUCCESS == zend_hash_quick_find(options, key, keylen, h, (void *) &zoption)) { - zval *option, *cached; - - option = http_zsep(type, *zoption); - cached = http_request_option_cache_ex(r, key, keylen, h, option); - - zval_ptr_dtor(&option); - return cached; - } - } - - return NULL; -} -/* }}} */ - -/* {{{ static inline zval *http_request_option_cache(http_request *, char *key, zval *) */ -static inline zval *_http_request_option_cache_ex(http_request *r, char *key, size_t keylen, ulong h, zval *opt TSRMLS_DC) -{ - ZVAL_ADDREF(opt); - - if (h) { - zend_hash_quick_update(&r->_cache.options, key, keylen, h, &opt, sizeof(zval *), NULL); - } else { - zend_hash_update(&r->_cache.options, key, keylen, &opt, sizeof(zval *), NULL); - } - - return opt; -} -/* }}} */ - -/* {{{ static inline int http_request_cookies_enabled(http_request *) */ -static inline int _http_request_cookies_enabled(http_request *request) { - http_request_storage *st; - - if (request->ch && (st = http_request_storage_get(request->ch)) && st->cookiestore) { - /* cookies are enabled */ - return 1; - } - return 0; -} -/* }}} */ - -#endif /* HTTP_HAVE_CURL */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_request_body_api.c b/http_request_body_api.c deleted file mode 100644 index 7d7f4f9..0000000 --- a/http_request_body_api.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_CURL -#include "php_http.h" - -#ifdef HTTP_HAVE_CURL - -#include "php_http_api.h" -#include "php_http_url_api.h" -#include "php_http_request_body_api.h" - -/* {{{ */ -typedef struct curl_httppost *post_data[2]; -static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC); -static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC); -/* }}} */ - -/* {{{ http_request_body *http_request_body_new() */ -PHP_HTTP_API http_request_body *_http_request_body_init_ex(http_request_body *body, int type, void *data, size_t size, zend_bool free ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - if (!body) { - body = emalloc_rel(sizeof(http_request_body)); - } - - body->type = type; - body->free = free; - body->priv = 0; - body->data = data; - body->size = size; - - return body; -} -/* }}} */ - -/* {{{ http_request_body *http_request_body_fill(http_request_body *body, HashTable *, HashTable *) */ -PHP_HTTP_API http_request_body *_http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) -{ - if (files && (zend_hash_num_elements(files) > 0)) { - struct curl_httppost *http_post_data[2] = {NULL, NULL}; - - if (fields && SUCCESS != recursive_fields(http_post_data, fields, NULL TSRMLS_CC)) { - return NULL; - } - if (SUCCESS != recursive_files(http_post_data, files, NULL TSRMLS_CC)) { - return NULL; - } - return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CURLPOST, http_post_data[0], 0, 1); - } else if (fields) { - char *encoded; - size_t encoded_len; - - if (SUCCESS != http_urlencode_hash_ex(fields, 1, NULL, 0, &encoded, &encoded_len)) { - http_error(HE_WARNING, HTTP_E_ENCODING, "Could not encode post data"); - return NULL; - } - - return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, encoded, encoded_len, 1); - } else { - return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, estrndup("", 0), 0, 1); - } -} - -/* STATUS http_request_body_encode(http_request_body *, char**, size_t *) */ -PHP_HTTP_API STATUS _http_request_body_encode(http_request_body *body, char **buf, size_t *len TSRMLS_DC) -{ - switch (body->type) { - case HTTP_REQUEST_BODY_CURLPOST: - { -#ifdef HAVE_CURL_FORMGET - phpstr str; - - phpstr_init_ex(&str, 0x8000, 0); - if (curl_formget(body->data, &str, (curl_formget_callback) phpstr_append)) { - phpstr_dtor(&str); - } else { - phpstr_fix(&str); - *buf = PHPSTR_VAL(&str); - *len = PHPSTR_LEN(&str); - return SUCCESS; - } -#endif - break; - } - - case HTTP_REQUEST_BODY_CSTRING: - *buf = estrndup(body->data, *len = body->size); - return SUCCESS; - - default: - break; - } - return FAILURE; -} -/* }}} */ - -/* {{{ void http_request_body_dtor(http_request_body *) */ -PHP_HTTP_API void _http_request_body_dtor(http_request_body *body TSRMLS_DC) -{ - if (body) { - if (body->free) { - switch (body->type) { - case HTTP_REQUEST_BODY_CSTRING: - if (body->data) { - efree(body->data); - } - break; - - case HTTP_REQUEST_BODY_CURLPOST: - curl_formfree(body->data); - break; - - case HTTP_REQUEST_BODY_UPLOADFILE: - php_stream_close(body->data); - break; - } - } - memset(body, 0, sizeof(http_request_body)); - } -} -/* }}} */ - -/* {{{ void http_request_body_free(http_request_body *) */ -PHP_HTTP_API void _http_request_body_free(http_request_body **body TSRMLS_DC) -{ - if (*body) { - http_request_body_dtor(*body); - efree(*body); - *body = NULL; - } -} -/* }}} */ - -static inline char *format_key(uint type, char *str, ulong num, const char *prefix, int numeric_key_for_empty_prefix) { - char *new_key = NULL; - - if (prefix && *prefix) { - if (type == HASH_KEY_IS_STRING) { - spprintf(&new_key, 0, "%s[%s]", prefix, str); - } else { - spprintf(&new_key, 0, "%s[%lu]", prefix, num); - } - } else if (type == HASH_KEY_IS_STRING) { - new_key = estrdup(str); - } else if (numeric_key_for_empty_prefix) { - spprintf(&new_key, 0, "%lu", num); - } - - return new_key; -} - -/* {{{ static STATUS recursive_fields(post_data d, HashTable *f, const char *p TSRMLS_DC) */ -static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC) { - HashKey key = initHashKey(0); - zval **data_ptr; - HashPosition pos; - char *new_key = NULL; - CURLcode err = 0; - - if (fields && !fields->nApplyCount) { - FOREACH_HASH_KEYVAL(pos, fields, key, data_ptr) { - if (key.type != HASH_KEY_IS_STRING || *key.str) { - new_key = format_key(key.type, key.str, key.num, prefix, 1); - - switch (Z_TYPE_PP(data_ptr)) { - case IS_ARRAY: - case IS_OBJECT: { - STATUS status; - - ++fields->nApplyCount; - status = recursive_fields(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC); - --fields->nApplyCount; - - if (SUCCESS != status) { - goto error; - } - break; - } - - default: { - zval *data = http_zsep(IS_STRING, *data_ptr); - - err = curl_formadd(&http_post_data[0], &http_post_data[1], - CURLFORM_COPYNAME, new_key, - CURLFORM_COPYCONTENTS, Z_STRVAL_P(data), - CURLFORM_CONTENTSLENGTH, (long) Z_STRLEN_P(data), - CURLFORM_END - ); - - zval_ptr_dtor(&data); - - if (CURLE_OK != err) { - goto error; - } - break; - } - } - STR_FREE(new_key); - } - } - } - - return SUCCESS; - -error: - if (new_key) { - efree(new_key); - } - if (http_post_data[0]) { - curl_formfree(http_post_data[0]); - } - if (err) { - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: %s", curl_easy_strerror(err)); - } else { - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: unknown error"); - } - return FAILURE; -} -/* }}} */ - -/* {{{ static STATUS recursive_files(post_data d, HashTable *f, const char *p TSRMLS_DC) */ -static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC) { - HashKey key = initHashKey(0); - zval **data_ptr; - HashPosition pos; - char *new_key = NULL; - CURLcode err = 0; - - if (files && !files->nApplyCount) { - FOREACH_HASH_KEYVAL(pos, files, key, data_ptr) { - zval **file_ptr, **type_ptr, **name_ptr; - - if (key.type != HASH_KEY_IS_STRING || *key.str) { - new_key = format_key(key.type, key.str, key.num, prefix, 0); - - if (Z_TYPE_PP(data_ptr) != IS_ARRAY && Z_TYPE_PP(data_ptr) != IS_OBJECT) { - if (new_key || key.type == HASH_KEY_IS_STRING) { - http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%s'", new_key ? new_key : key.str); - } else { - http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%lu'", key.num); - } - } else if ( SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "name", sizeof("name"), (void *) &name_ptr) || - SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "type", sizeof("type"), (void *) &type_ptr) || - SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "file", sizeof("file"), (void *) &file_ptr)) { - STATUS status; - - ++files->nApplyCount; - status = recursive_files(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC); - --files->nApplyCount; - - if (SUCCESS != status) { - goto error; - } - } else { - const char *path; - zval *file = http_zsep(IS_STRING, *file_ptr); - zval *type = http_zsep(IS_STRING, *type_ptr); - zval *name = http_zsep(IS_STRING, *name_ptr); - - HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(file), goto error); - - /* this is blatant but should be sufficient for most cases */ - if (strncasecmp(Z_STRVAL_P(file), "file://", lenof("file://"))) { - path = Z_STRVAL_P(file); - } else { - path = Z_STRVAL_P(file) + lenof("file://"); - } - - if (new_key) { - char *tmp_key = format_key(HASH_KEY_IS_STRING, Z_STRVAL_P(name), 0, new_key, 0); - STR_SET(new_key, tmp_key); - } - - err = curl_formadd(&http_post_data[0], &http_post_data[1], - CURLFORM_COPYNAME, new_key ? new_key : Z_STRVAL_P(name), - CURLFORM_FILE, path, - CURLFORM_CONTENTTYPE, Z_STRVAL_P(type), - CURLFORM_END - ); - - zval_ptr_dtor(&file); - zval_ptr_dtor(&type); - zval_ptr_dtor(&name); - - if (CURLE_OK != err) { - goto error; - } - } - STR_FREE(new_key); - } - } - } - - return SUCCESS; - -error: - if (new_key) { - efree(new_key); - } - if (http_post_data[0]) { - curl_formfree(http_post_data[0]); - } - if (err) { - http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: %s", curl_easy_strerror(err)); - } else { - http_error(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: unknown error"); - } - return FAILURE; -} -/* }}} */ - -#endif /* HTTP_HAVE_CURL */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/http_request_datashare_api.c b/http_request_datashare_api.c deleted file mode 100644 index 1f48b7c..0000000 --- a/http_request_datashare_api.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_CURL -#include "php_http.h" - -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) - -#include "php_http_api.h" -#include "php_http_persistent_handle_api.h" -#include "php_http_request_datashare_api.h" -#include "php_http_request_api.h" -#include "php_http_request_object.h" - -static HashTable http_request_datashare_options; -static http_request_datashare http_request_datashare_global; -static int http_request_datashare_compare_handles(void *h1, void *h2); -static void http_request_datashare_destroy_handles(void *el); -#ifdef ZTS -static void *http_request_datashare_locks_init(void); -static void http_request_datashare_locks_dtor(void *l); -static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr); -static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr); -#endif - -http_request_datashare *_http_request_datashare_global_get(void) -{ - return &http_request_datashare_global; -} - -PHP_MINIT_FUNCTION(http_request_datashare) -{ - curl_lock_data val; - - if (SUCCESS != http_persistent_handle_provide("http_request_datashare", curl_share_init, (http_persistent_handle_dtor) curl_share_cleanup, NULL)) { - return FAILURE; - } -#ifdef ZTS - if (SUCCESS != http_persistent_handle_provide("http_request_datashare_lock", http_request_datashare_locks_init, http_request_datashare_locks_dtor, NULL)) { - return FAILURE; - } -#endif - - if (!http_request_datashare_init_ex(&http_request_datashare_global, 1)) { - return FAILURE; - } - - zend_hash_init(&http_request_datashare_options, 4, NULL, NULL, 1); -#define ADD_DATASHARE_OPT(name, opt) \ - val = opt; \ - zend_hash_add(&http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL) - ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE); - ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS); - ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION); - ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT); - - return SUCCESS; -} - -PHP_MSHUTDOWN_FUNCTION(http_request_datashare) -{ - http_request_datashare_dtor(&http_request_datashare_global); - zend_hash_destroy(&http_request_datashare_options); - - return SUCCESS; -} - -PHP_RINIT_FUNCTION(http_request_datashare) -{ - zend_llist_init(&HTTP_G->request.datashare.handles, sizeof(zval *), http_request_datashare_destroy_handles, 0); - - return SUCCESS; -} - -PHP_RSHUTDOWN_FUNCTION(http_request_datashare) -{ - zend_llist_destroy(&HTTP_G->request.datashare.handles); - - return SUCCESS; -} - -PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC) -{ - zend_bool free_share; - - if ((free_share = !share)) { - share = pemalloc(sizeof(http_request_datashare), persistent); - } - memset(share, 0, sizeof(http_request_datashare)); - - if (SUCCESS != http_persistent_handle_acquire("http_request_datashare", &share->ch)) { - if (free_share) { - pefree(share, persistent); - } - return NULL; - } - - if (!(share->persistent = persistent)) { - share->handle.list = emalloc(sizeof(zend_llist)); - zend_llist_init(share->handle.list, sizeof(zval *), ZVAL_PTR_DTOR, 0); -#ifdef ZTS - } else { - if (SUCCESS == http_persistent_handle_acquire("http_request_datashare_lock", (void *) &share->handle.locks)) { - curl_share_setopt(share->ch, CURLSHOPT_LOCKFUNC, http_request_datashare_lock_func); - curl_share_setopt(share->ch, CURLSHOPT_UNLOCKFUNC, http_request_datashare_unlock_func); - curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share->handle.locks); - } -#endif - } - - return share; -} - -PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC) -{ - CURLcode rc; - getObjectEx(http_request_object, obj, request); - - if (obj->share) { - if (obj->share == share) { - return SUCCESS; - } else if (SUCCESS != http_request_datashare_detach(obj->share, request)) { - return FAILURE; - } - } - - HTTP_CHECK_CURL_INIT(obj->request->ch, http_curl_init_ex(obj->request->ch, obj->request), return FAILURE); - if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, share->ch))) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not attach HttpRequest object(#%d) to the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_easy_strerror(rc)); - return FAILURE; - } - - obj->share = share; - ZVAL_ADDREF(request); - zend_llist_add_element(HTTP_RSHARE_HANDLES(share), (void *) &request); - - return SUCCESS; -} - -PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC) -{ - CURLcode rc; - getObjectEx(http_request_object, obj, request); - - if (!obj->share) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request)); - } else if (obj->share != share) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request)); - } else if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL))) { - 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)); - } else { - obj->share = NULL; - zend_llist_del_element(HTTP_RSHARE_HANDLES(share), request, http_request_datashare_compare_handles); - return SUCCESS; - } - return FAILURE; -} - -PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC) -{ - zval **r; - - while ((r = zend_llist_get_first(HTTP_RSHARE_HANDLES(share)))) { - http_request_datashare_detach(share, *r); - } -} - -PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC) -{ - if (!share->persistent) { - zend_llist_destroy(share->handle.list); - efree(share->handle.list); - } - http_persistent_handle_release("http_request_datashare", &share->ch); -#ifdef ZTS - if (share->persistent) { - http_persistent_handle_release("http_request_datashare_lock", (void *) &share->handle.locks); - } -#endif -} - -PHP_HTTP_API void _http_request_datashare_free(http_request_datashare **share TSRMLS_DC) -{ - http_request_datashare_dtor(*share); - pefree(*share, (*share)->persistent); - *share = NULL; -} - -PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC) -{ - curl_lock_data *opt; - CURLSHcode rc; - - if (SUCCESS == zend_hash_find(&http_request_datashare_options, (char *) option, option_len + 1, (void *) &opt)) { - if (CURLSHE_OK == (rc = curl_share_setopt(share->ch, enable ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, *opt))) { - return SUCCESS; - } - http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not %s sharing of %s data: %s", enable ? "enable" : "disable", option, curl_share_strerror(rc)); - } - return FAILURE; -} - -static int http_request_datashare_compare_handles(void *h1, void *h2) -{ - return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2)); -} - -static void http_request_datashare_destroy_handles(void *el) -{ - zval **r = (zval **) el; - TSRMLS_FETCH(); - - { /* gcc 2.95 needs these braces */ - getObjectEx(http_request_object, obj, *r); - - curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL); - zval_ptr_dtor(r); - } -} - -#ifdef ZTS -static void *http_request_datashare_locks_init(void) -{ - int i; - http_request_datashare_lock *locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(http_request_datashare_lock), 1); - - if (locks) { - for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) { - locks[i].mx = tsrm_mutex_alloc(); - } - } - - return locks; -} - -static void http_request_datashare_locks_dtor(void *l) -{ - int i; - http_request_datashare_lock *locks = (http_request_datashare_lock *) l; - - for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) { - tsrm_mutex_free(locks[i].mx); - } - pefree(locks, 1); -} - -static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr) -{ - http_request_datashare_lock *locks = (http_request_datashare_lock *) userptr; - - /* TSRM can't distinguish shared/exclusive locks */ - tsrm_mutex_lock(locks[data].mx); - locks[data].ch = handle; -} - -static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr) -{ - http_request_datashare_lock *locks = (http_request_datashare_lock *) userptr; - - if (locks[data].ch == handle) { - tsrm_mutex_unlock(locks[data].mx); - } -} -#endif - -#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */ - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_request_info.c b/http_request_info.c deleted file mode 100644 index b817841..0000000 --- a/http_request_info.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_CURL -#include "php_http.h" - -#ifdef HTTP_HAVE_CURL -#include "php_http_request_api.h" - -/* {{{ void http_request_info(http_request *, HashTable *) */ -PHP_HTTP_API void _http_request_info(http_request *request, HashTable *info) -{ - char *c; - long l; - double d; - struct curl_slist *s, *p; - zval *subarray, array; - INIT_ZARR(array, info); - - /* BEGIN */ - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_EFFECTIVE_URL, &c)) { - add_assoc_string_ex(&array, "effective_url", sizeof("effective_url"), c ? c : "", 1); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_RESPONSE_CODE, &l)) { - add_assoc_long_ex(&array, "response_code", sizeof("response_code"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_TOTAL_TIME, &d)) { - add_assoc_double_ex(&array, "total_time", sizeof("total_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_NAMELOOKUP_TIME, &d)) { - add_assoc_double_ex(&array, "namelookup_time", sizeof("namelookup_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONNECT_TIME, &d)) { - add_assoc_double_ex(&array, "connect_time", sizeof("connect_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PRETRANSFER_TIME, &d)) { - add_assoc_double_ex(&array, "pretransfer_time", sizeof("pretransfer_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SIZE_UPLOAD, &d)) { - add_assoc_double_ex(&array, "size_upload", sizeof("size_upload"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SIZE_DOWNLOAD, &d)) { - add_assoc_double_ex(&array, "size_download", sizeof("size_download"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SPEED_DOWNLOAD, &d)) { - add_assoc_double_ex(&array, "speed_download", sizeof("speed_download"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SPEED_UPLOAD, &d)) { - add_assoc_double_ex(&array, "speed_upload", sizeof("speed_upload"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_HEADER_SIZE, &l)) { - add_assoc_long_ex(&array, "header_size", sizeof("header_size"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REQUEST_SIZE, &l)) { - add_assoc_long_ex(&array, "request_size", sizeof("request_size"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SSL_VERIFYRESULT, &l)) { - add_assoc_long_ex(&array, "ssl_verifyresult", sizeof("ssl_verifyresult"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_FILETIME, &l)) { - add_assoc_long_ex(&array, "filetime", sizeof("filetime"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) { - add_assoc_double_ex(&array, "content_length_download", sizeof("content_length_download"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) { - add_assoc_double_ex(&array, "content_length_upload", sizeof("content_length_upload"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_STARTTRANSFER_TIME, &d)) { - add_assoc_double_ex(&array, "starttransfer_time", sizeof("starttransfer_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONTENT_TYPE, &c)) { - add_assoc_string_ex(&array, "content_type", sizeof("content_type"), c ? c : "", 1); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REDIRECT_TIME, &d)) { - add_assoc_double_ex(&array, "redirect_time", sizeof("redirect_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REDIRECT_COUNT, &l)) { - add_assoc_long_ex(&array, "redirect_count", sizeof("redirect_count"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_HTTP_CONNECTCODE, &l)) { - add_assoc_long_ex(&array, "connect_code", sizeof("connect_code"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_HTTPAUTH_AVAIL, &l)) { - add_assoc_long_ex(&array, "httpauth_avail", sizeof("httpauth_avail"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PROXYAUTH_AVAIL, &l)) { - add_assoc_long_ex(&array, "proxyauth_avail", sizeof("proxyauth_avail"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_OS_ERRNO, &l)) { - add_assoc_long_ex(&array, "os_errno", sizeof("os_errno"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_NUM_CONNECTS, &l)) { - add_assoc_long_ex(&array, "num_connects", sizeof("num_connects"), l); - } - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_SSL_ENGINES, &s)) { - MAKE_STD_ZVAL(subarray); - array_init(subarray); - for (p = s; p; p = p->next) { - if (p->data) { - add_next_index_string(subarray, p->data, 1); - } - } - add_assoc_zval_ex(&array, "ssl_engines", sizeof("ssl_engines"), subarray); - curl_slist_free_all(s); - } -#if HTTP_CURL_VERSION(7,14,1) - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_COOKIELIST, &s)) { - MAKE_STD_ZVAL(subarray); - array_init(subarray); - for (p = s; p; p = p->next) { - if (p->data) { - add_next_index_string(subarray, p->data, 1); - } - } - add_assoc_zval_ex(&array, "cookies", sizeof("cookies"), subarray); - curl_slist_free_all(s); - } -#endif -#if HTTP_CURL_VERSION(7,18,2) - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_REDIRECT_URL, &c)) { - add_assoc_string_ex(&array, "redirect_url", sizeof("redirect_url"), c ? c : "", 1); - } -#endif -#if HTTP_CURL_VERSION(7,19,0) - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PRIMARY_IP, &c)) { - add_assoc_string_ex(&array, "primary_ip", sizeof("primary_ip"), c ? c : "", 1); - } -#endif -#if HTTP_CURL_VERSION(7,19,0) - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_APPCONNECT_TIME, &d)) { - add_assoc_double_ex(&array, "appconnect_time", sizeof("appconnect_time"), d); - } -#endif -#if HTTP_CURL_VERSION(7,19,4) - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CONDITION_UNMET, &l)) { - add_assoc_long_ex(&array, "condition_unmet", sizeof("condition_unmet"), l); - } -#endif -#if HTTP_CURL_VERSION(7,21,0) - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_PRIMARY_PORT, &l)) { - add_assoc_long_ex(&array, "primary_port", sizeof("primary_port"), l); - } -#endif -#if HTTP_CURL_VERSION(7,21,0) - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_LOCAL_IP, &c)) { - add_assoc_string_ex(&array, "local_ip", sizeof("local_ip"), c ? c : "", 1); - } -#endif -#if HTTP_CURL_VERSION(7,21,0) - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_LOCAL_PORT, &l)) { - add_assoc_long_ex(&array, "local_port", sizeof("local_port"), l); - } -#endif -/* END */ -#if HTTP_CURL_VERSION(7,19,1) && defined(HTTP_HAVE_OPENSSL) - { - int i; - zval *ci_array; - struct curl_certinfo *ci; - char *colon, *keyname; - - if (CURLE_OK == curl_easy_getinfo(request->ch, CURLINFO_CERTINFO, &ci)) { - MAKE_STD_ZVAL(ci_array); - array_init(ci_array); - - for (i = 0; i < ci->num_of_certs; ++i) { - s = ci->certinfo[i]; - - MAKE_STD_ZVAL(subarray); - array_init(subarray); - for (p = s; p; p = p->next) { - if (p->data) { - if ((colon = strchr(p->data, ':'))) { - keyname = estrndup(p->data, colon - p->data); - add_assoc_string_ex(subarray, keyname, colon - p->data + 1, colon + 1, 1); - efree(keyname); - } else { - add_next_index_string(subarray, p->data, 1); - } - } - } - add_next_index_zval(ci_array, subarray); - } - add_assoc_zval_ex(&array, "certinfo", sizeof("certinfo"), ci_array); - } - } -#endif - add_assoc_string_ex(&array, "error", sizeof("error"), http_request_storage_get(request->ch)->errorbuffer, 1); -} -/* }}} */ - -#endif /* HTTP_HAVE_CURL */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/http_request_method_api.c b/http_request_method_api.c deleted file mode 100644 index 2f99a91..0000000 --- a/http_request_method_api.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_CURL -#include "php_http.h" - -#include "php_http_api.h" -#include "php_http_request_api.h" -#include "php_http_request_method_api.h" - -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY) -# include "php_http_request_object.h" -#endif - -/* {{{ char *http_request_methods[] */ -static const char *const http_request_methods[] = { - "UNKNOWN", - /* HTTP/1.1 */ - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "OPTIONS", - "TRACE", - "CONNECT", - /* WebDAV - RFC 2518 */ - "PROPFIND", - "PROPPATCH", - "MKCOL", - "COPY", - "MOVE", - "LOCK", - "UNLOCK", - /* WebDAV Versioning - RFC 3253 */ - "VERSION-CONTROL", - "REPORT", - "CHECKOUT", - "CHECKIN", - "UNCHECKOUT", - "MKWORKSPACE", - "UPDATE", - "LABEL", - "MERGE", - "BASELINE-CONTROL", - "MKACTIVITY", - /* WebDAV Access Control - RFC 3744 */ - "ACL", - NULL -}; -/* }}} */ - -/* {{{ */ -PHP_MINIT_FUNCTION(http_request_method) -{ - /* HTTP/1.1 */ - HTTP_LONG_CONSTANT("HTTP_METH_GET", HTTP_GET); - HTTP_LONG_CONSTANT("HTTP_METH_HEAD", HTTP_HEAD); - HTTP_LONG_CONSTANT("HTTP_METH_POST", HTTP_POST); - HTTP_LONG_CONSTANT("HTTP_METH_PUT", HTTP_PUT); - HTTP_LONG_CONSTANT("HTTP_METH_DELETE", HTTP_DELETE); - HTTP_LONG_CONSTANT("HTTP_METH_OPTIONS", HTTP_OPTIONS); - HTTP_LONG_CONSTANT("HTTP_METH_TRACE", HTTP_TRACE); - HTTP_LONG_CONSTANT("HTTP_METH_CONNECT", HTTP_CONNECT); - /* WebDAV - RFC 2518 */ - HTTP_LONG_CONSTANT("HTTP_METH_PROPFIND", HTTP_PROPFIND); - HTTP_LONG_CONSTANT("HTTP_METH_PROPPATCH", HTTP_PROPPATCH); - HTTP_LONG_CONSTANT("HTTP_METH_MKCOL", HTTP_MKCOL); - HTTP_LONG_CONSTANT("HTTP_METH_COPY", HTTP_COPY); - HTTP_LONG_CONSTANT("HTTP_METH_MOVE", HTTP_MOVE); - HTTP_LONG_CONSTANT("HTTP_METH_LOCK", HTTP_LOCK); - HTTP_LONG_CONSTANT("HTTP_METH_UNLOCK", HTTP_UNLOCK); - /* WebDAV Versioning - RFC 3253 */ - HTTP_LONG_CONSTANT("HTTP_METH_VERSION_CONTROL", HTTP_VERSION_CONTROL); - HTTP_LONG_CONSTANT("HTTP_METH_REPORT", HTTP_REPORT); - HTTP_LONG_CONSTANT("HTTP_METH_CHECKOUT", HTTP_CHECKOUT); - HTTP_LONG_CONSTANT("HTTP_METH_CHECKIN", HTTP_CHECKIN); - HTTP_LONG_CONSTANT("HTTP_METH_UNCHECKOUT", HTTP_UNCHECKOUT); - HTTP_LONG_CONSTANT("HTTP_METH_MKWORKSPACE", HTTP_MKWORKSPACE); - HTTP_LONG_CONSTANT("HTTP_METH_UPDATE", HTTP_UPDATE); - HTTP_LONG_CONSTANT("HTTP_METH_LABEL", HTTP_LABEL); - HTTP_LONG_CONSTANT("HTTP_METH_MERGE", HTTP_MERGE); - HTTP_LONG_CONSTANT("HTTP_METH_BASELINE_CONTROL", HTTP_BASELINE_CONTROL); - HTTP_LONG_CONSTANT("HTTP_METH_MKACTIVITY", HTTP_MKACTIVITY); - /* WebDAV Access Control - RFC 3744 */ - HTTP_LONG_CONSTANT("HTTP_METH_ACL", HTTP_ACL); - - return SUCCESS; -} - -static void free_method(void *el) -{ - efree(*(char **)el); -} - -static void unregister_method(const char *name TSRMLS_DC) -{ - char *ptr, tmp[sizeof("HTTP_METH_") + HTTP_REQUEST_METHOD_MAXLEN] = "HTTP_METH_"; - - strlcpy(tmp + lenof("HTTP_METH_"), name, HTTP_REQUEST_METHOD_MAXLEN); - for (ptr = tmp + lenof("HTTP_METH_"); *ptr; ++ptr) { - if (*ptr == '-') { - *ptr = '_'; - } - } - -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY) - if (SUCCESS != zend_hash_del(&http_request_object_ce->constants_table, tmp + lenof("HTTP_"), strlen(tmp + lenof("HTTP_")) + 1)) { - http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: HttpRequest::%s", tmp + lenof("HTTP_")); - } -#endif - if (SUCCESS != zend_hash_del(EG(zend_constants), tmp, strlen(tmp) + 1)) { - http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: %s", tmp); - } -} - -PHP_RINIT_FUNCTION(http_request_method) -{ - HashTable ht; - - zend_hash_init(&HTTP_G->request.methods.registered, 0, NULL, free_method, 0); -#define HTTP_METH_REG(m) \ - { \ - char *_m=estrdup(m); \ - zend_hash_next_index_insert(&HTTP_G->request.methods.registered, (void *) &_m, sizeof(char *), NULL); \ - } - HTTP_METH_REG("UNKNOWN"); - /* HTTP/1.1 */ - HTTP_METH_REG("GET"); - HTTP_METH_REG("HEAD"); - HTTP_METH_REG("POST"); - HTTP_METH_REG("PUT"); - HTTP_METH_REG("DELETE"); - HTTP_METH_REG("OPTIONS"); - HTTP_METH_REG("TRACE"); - HTTP_METH_REG("CONNECT"); - /* WebDAV - RFC 2518 */ - HTTP_METH_REG("PROPFIND"); - HTTP_METH_REG("PROPPATCH"); - HTTP_METH_REG("MKCOL"); - HTTP_METH_REG("COPY"); - HTTP_METH_REG("MOVE"); - HTTP_METH_REG("LOCK"); - HTTP_METH_REG("UNLOCK"); - /* WebDAV Versioning - RFC 3253 */ - HTTP_METH_REG("VERSION-CONTROL"); - HTTP_METH_REG("REPORT"); - HTTP_METH_REG("CHECKOUT"); - HTTP_METH_REG("CHECKIN"); - HTTP_METH_REG("UNCHECKOUT"); - HTTP_METH_REG("MKWORKSPACE"); - HTTP_METH_REG("UPDATE"); - HTTP_METH_REG("LABEL"); - HTTP_METH_REG("MERGE"); - HTTP_METH_REG("BASELINE-CONTROL"); - HTTP_METH_REG("MKACTIVITY"); - /* WebDAV Access Control - RFC 3744 */ - HTTP_METH_REG("ACL"); - - zend_hash_init(&ht, 0, NULL, ZVAL_PTR_DTOR, 0); - if (*HTTP_G->request.methods.custom && SUCCESS == http_parse_params(HTTP_G->request.methods.custom, HTTP_PARAMS_DEFAULT, &ht)) { - HashPosition pos; - zval **val; - - FOREACH_HASH_VAL(pos, &ht, val) { - if (Z_TYPE_PP(val) == IS_STRING) { - http_request_method_register(Z_STRVAL_PP(val), Z_STRLEN_PP(val)); - } - } - } - zend_hash_destroy(&ht); - - return SUCCESS; -} - -PHP_RSHUTDOWN_FUNCTION(http_request_method) -{ - char **name; - int i, c = zend_hash_next_free_element(&HTTP_G->request.methods.registered); - - for (i = HTTP_MAX_REQUEST_METHOD; i < c; ++i) { - if (SUCCESS == zend_hash_index_find(&HTTP_G->request.methods.registered, i, (void *) &name)) { - unregister_method(*name TSRMLS_CC); - } - } - - zend_hash_destroy(&HTTP_G->request.methods.registered); - return SUCCESS; -} - -#define http_request_method_cncl(m, c) _http_request_method_cncl_ex((m), strlen(m), (c) TSRMLS_CC) -#define http_request_method_cncl_ex(m, l, c) _http_request_method_cncl_ex((m), (l), (c) TSRMLS_CC) -static STATUS _http_request_method_cncl_ex(const char *method_name, int method_name_len, char **cnst TSRMLS_DC) -{ - int i; - char *cncl; - - if (method_name_len >= HTTP_REQUEST_METHOD_MAXLEN) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method too long (%s)", method_name); - } - cncl = emalloc(method_name_len + 1); - - for (i = 0; i < method_name_len; ++i) { - switch (method_name[i]) { - case '-': - case '_': - cncl[i] = method_name[i]; - break; - - default: - if (!HTTP_IS_CTYPE(alnum, method_name[i])) { - efree(cncl); - http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method contains illegal characters (%s)", method_name); - return FAILURE; - } - cncl[i] = HTTP_TO_CTYPE(upper, method_name[i]); - break; - } - } - cncl[method_name_len] = '\0'; - - *cnst = cncl; - return SUCCESS; -} - -PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC) -{ - char **name; - - if (SUCCESS == zend_hash_index_find(&HTTP_G->request.methods.registered, m, (void *) &name)) { - return *name; - } - return "UNKNOWN"; -} - -PHP_HTTP_API int _http_request_method_exists(int by_name, http_request_method id_num, const char *id_str TSRMLS_DC) -{ - char *id_dup; - - if (by_name && (SUCCESS == http_request_method_cncl(id_str, &id_dup))) { - char **name; - HashPosition pos; - HashKey key = initHashKey(0); - - FOREACH_HASH_KEYVAL(pos, &HTTP_G->request.methods.registered, key, name) { - if (key.type == HASH_KEY_IS_LONG && !strcmp(*name, id_dup)) { - efree(id_dup); - return key.num; - } - } - efree(id_dup); - } else if (zend_hash_index_exists(&HTTP_G->request.methods.registered, id_num)){ - return id_num; - } - return 0; -} - -PHP_HTTP_API int _http_request_method_register(const char *method_str, int method_len TSRMLS_DC) -{ - char *method_dup, *ptr, tmp[sizeof("HTTP_METH_") + HTTP_REQUEST_METHOD_MAXLEN] = "HTTP_METH_"; - int method_num = http_request_method_exists(1, 0, method_str); - - if (!method_num && (SUCCESS == http_request_method_cncl_ex(method_str, method_len, &method_dup))) { - method_num = zend_hash_next_free_element(&HTTP_G->request.methods.registered); - zend_hash_index_update(&HTTP_G->request.methods.registered, method_num, (void *) &method_dup, sizeof(char *), NULL); - - strlcpy(tmp + lenof("HTTP_METH_"), method_dup, HTTP_REQUEST_METHOD_MAXLEN); - for (ptr = tmp + lenof("HTTP_METH_"); *ptr; ++ptr) { - if (*ptr == '-') { - *ptr = '_'; - } - } - - zend_register_long_constant(tmp, strlen(tmp) + 1, method_num, CONST_CS, http_module_number TSRMLS_CC); -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY) - zend_declare_class_constant_long(http_request_object_ce, tmp + lenof("HTTP_"), strlen(tmp + lenof("HTTP_")), method_num TSRMLS_CC); -#endif - } - - return method_num; -} - -PHP_HTTP_API STATUS _http_request_method_unregister(int method TSRMLS_DC) -{ - char **name; - - if (HTTP_STD_REQUEST_METHOD(method)) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Standard request methods cannot be unregistered"); - return FAILURE; - } - - if (SUCCESS != zend_hash_index_find(&HTTP_G->request.methods.registered, method, (void *) &name)) { - http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Custom request method with id %d does not exist", method); - return FAILURE; - } - - unregister_method(*name TSRMLS_CC); - - zend_hash_index_del(&HTTP_G->request.methods.registered, method); - return SUCCESS; -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_request_object.c b/http_request_object.c deleted file mode 100644 index f4f27cf..0000000 --- a/http_request_object.c +++ /dev/null @@ -1,1931 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_CURL -#include "php_http.h" - -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) - -#include "zend_interfaces.h" - -#include "php_http_api.h" -#include "php_http_cookie_api.h" -#include "php_http_exception_object.h" -#include "php_http_message_api.h" -#include "php_http_message_object.h" -#include "php_http_request_api.h" -#include "php_http_request_object.h" -#include "php_http_request_pool_api.h" -#include "php_http_url_api.h" - -#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpRequest, method, 0, req_args) -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpRequest, method, 0) -#define HTTP_REQUEST_ME(method, visibility) PHP_ME(HttpRequest, method, HTTP_ARGS(HttpRequest, method), visibility) -#define HTTP_REQUEST_ALIAS(method, func) HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpRequest, method)) -#define HTTP_REQUEST_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpRequest_##al), HTTP_ARGS(HttpRequest, al), vis) - -HTTP_BEGIN_ARGS(__construct, 0) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(method, 0) - HTTP_ARG_VAL(options, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(factory, 0) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(method, 0) - HTTP_ARG_VAL(options, 0) - HTTP_ARG_VAL(class_name, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getOptions); -HTTP_BEGIN_ARGS(setOptions, 0) - HTTP_ARG_VAL(options, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getSslOptions); -HTTP_BEGIN_ARGS(setSslOptions, 0) - HTTP_ARG_VAL(ssl_options, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(addSslOptions, 0) - HTTP_ARG_VAL(ssl_optins, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getHeaders); -HTTP_BEGIN_ARGS(setHeaders, 0) - HTTP_ARG_VAL(headers, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(addHeaders, 1) - HTTP_ARG_VAL(headers, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getCookies); -HTTP_BEGIN_ARGS(setCookies, 0) - HTTP_ARG_VAL(cookies, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(addCookies, 1) - HTTP_ARG_VAL(cookies, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(enableCookies); -HTTP_BEGIN_ARGS(resetCookies, 0) - HTTP_ARG_VAL(session_only, 0) -HTTP_END_ARGS; -HTTP_EMPTY_ARGS(flushCookies); - -HTTP_EMPTY_ARGS(getUrl); -HTTP_BEGIN_ARGS(setUrl, 1) - HTTP_ARG_VAL(url, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getMethod); -HTTP_BEGIN_ARGS(setMethod, 1) - HTTP_ARG_VAL(request_method, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getContentType); -HTTP_BEGIN_ARGS(setContentType, 1) - HTTP_ARG_VAL(content_type, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getQueryData); -HTTP_BEGIN_ARGS(setQueryData, 0) - HTTP_ARG_VAL(query_data, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(addQueryData, 1) - HTTP_ARG_VAL(query_data, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getPostFields); -HTTP_BEGIN_ARGS(setPostFields, 0) - HTTP_ARG_VAL(post_fields, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(addPostFields, 1) - HTTP_ARG_VAL(post_fields, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getPostFiles); -HTTP_BEGIN_ARGS(setPostFiles, 0) - HTTP_ARG_VAL(post_files, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(addPostFile, 2) - HTTP_ARG_VAL(formname, 0) - HTTP_ARG_VAL(filename, 0) - HTTP_ARG_VAL(content_type, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getBody); -HTTP_BEGIN_ARGS(setBody, 0) - HTTP_ARG_VAL(request_body_data, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(addBody, 1) - HTTP_ARG_VAL(request_body_data, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getPutFile); -HTTP_BEGIN_ARGS(setPutFile, 0) - HTTP_ARG_VAL(filename, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getPutData); -HTTP_BEGIN_ARGS(setPutData, 0) - HTTP_ARG_VAL(put_data, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(addPutData, 1) - HTTP_ARG_VAL(put_data, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getResponseData); -HTTP_BEGIN_ARGS(getResponseHeader, 0) - HTTP_ARG_VAL(name, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(getResponseCookies, 0) - HTTP_ARG_VAL(flags, 0) - HTTP_ARG_VAL(allowed_extras, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getResponseBody); -HTTP_EMPTY_ARGS(getResponseCode); -HTTP_EMPTY_ARGS(getResponseStatus); -HTTP_BEGIN_ARGS(getResponseInfo, 0) - HTTP_ARG_VAL(name, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getMessageClass); -HTTP_BEGIN_ARGS(setMessageClass, 1) - HTTP_ARG_VAL(message_class_name, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getResponseMessage); -HTTP_EMPTY_ARGS(getRawResponseMessage); -HTTP_EMPTY_ARGS(getRequestMessage); -HTTP_EMPTY_ARGS(getRawRequestMessage); -HTTP_EMPTY_ARGS(getHistory); -HTTP_EMPTY_ARGS(clearHistory); -HTTP_EMPTY_ARGS(send); - -HTTP_BEGIN_ARGS(get, 1) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(options, 0) - HTTP_ARG_VAL(info, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(head, 1) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(options, 0) - HTTP_ARG_VAL(info, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(postData, 2) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(data, 0) - HTTP_ARG_VAL(options, 0) - HTTP_ARG_VAL(info, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(postFields, 2) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(data, 0) - HTTP_ARG_VAL(options, 0) - HTTP_ARG_VAL(info, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(putData, 2) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(data, 0) - HTTP_ARG_VAL(options, 0) - HTTP_ARG_VAL(info, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(putFile, 2) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(file, 0) - HTTP_ARG_VAL(options, 0) - HTTP_ARG_VAL(info, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(putStream, 2) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(stream, 0) - HTTP_ARG_VAL(options, 0) - HTTP_ARG_VAL(info, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(methodRegister, 1) - HTTP_ARG_VAL(method_name, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(methodUnregister, 1) - HTTP_ARG_VAL(method, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(methodName, 1) - HTTP_ARG_VAL(method_id, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(methodExists, 1) - HTTP_ARG_VAL(method, 0) -HTTP_END_ARGS; - -#ifdef HAVE_CURL_FORMGET -HTTP_BEGIN_ARGS(encodeBody, 2) - HTTP_ARG_VAL(fields, 0) - HTTP_ARG_VAL(files, 0) -HTTP_END_ARGS; -#endif - -#define THIS_CE http_request_object_ce -zend_class_entry *http_request_object_ce; -zend_function_entry http_request_object_fe[] = { - HTTP_REQUEST_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - - HTTP_REQUEST_ME(setOptions, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getOptions, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(setSslOptions, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getSslOptions, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(addSslOptions, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(addHeaders, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getHeaders, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(setHeaders, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(addCookies, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getCookies, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(setCookies, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(enableCookies, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(resetCookies, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(flushCookies, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(setMethod, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getMethod, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(setUrl, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getUrl, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(setContentType, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getContentType, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(setQueryData, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getQueryData, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(addQueryData, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(setPostFields, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getPostFields, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(addPostFields, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(setBody, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getBody, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(addBody, ZEND_ACC_PUBLIC) - HTTP_REQUEST_MALIAS(setRawPostData, setBody, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) - HTTP_REQUEST_MALIAS(getRawPostData, getBody, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) - HTTP_REQUEST_MALIAS(addRawPostData, addBody, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) - - HTTP_REQUEST_ME(setPostFiles, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(addPostFile, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getPostFiles, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(setPutFile, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getPutFile, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(setPutData, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getPutData, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(addPutData, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(send, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(getResponseData, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getResponseHeader, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getResponseCookies, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getResponseCode, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getResponseStatus, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getResponseBody, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getResponseInfo, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getResponseMessage, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getRawResponseMessage, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getRequestMessage, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getRawRequestMessage, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(getHistory, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(clearHistory, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(getMessageClass, ZEND_ACC_PUBLIC) - HTTP_REQUEST_ME(setMessageClass, ZEND_ACC_PUBLIC) - - HTTP_REQUEST_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - - HTTP_REQUEST_ALIAS(get, http_get) - HTTP_REQUEST_ALIAS(head, http_head) - HTTP_REQUEST_ALIAS(postData, http_post_data) - HTTP_REQUEST_ALIAS(postFields, http_post_fields) - HTTP_REQUEST_ALIAS(putData, http_put_data) - HTTP_REQUEST_ALIAS(putFile, http_put_file) - HTTP_REQUEST_ALIAS(putStream, http_put_stream) - - HTTP_REQUEST_ALIAS(methodRegister, http_request_method_register) - HTTP_REQUEST_ALIAS(methodUnregister, http_request_method_unregister) - HTTP_REQUEST_ALIAS(methodName, http_request_method_name) - HTTP_REQUEST_ALIAS(methodExists, http_request_method_exists) -#ifdef HAVE_CURL_FORMGET - HTTP_REQUEST_ALIAS(encodeBody, http_request_body_encode) -#endif - EMPTY_FUNCTION_ENTRY -}; -static zend_object_handlers http_request_object_handlers; - -PHP_MINIT_FUNCTION(http_request_object) -{ - HTTP_REGISTER_CLASS_EX(HttpRequest, http_request_object, NULL, 0); - http_request_object_handlers.clone_obj = _http_request_object_clone_obj; - - zend_declare_property_null(THIS_CE, ZEND_STRS("options")-1, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("postFields")-1, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("postFiles")-1, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("responseInfo")-1, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("responseMessage")-1, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(THIS_CE, ZEND_STRS("responseCode")-1, 0, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(THIS_CE, ZEND_STRS("responseStatus")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(THIS_CE, ZEND_STRS("method")-1, HTTP_GET, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(THIS_CE, ZEND_STRS("url")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(THIS_CE, ZEND_STRS("contentType")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(THIS_CE, ZEND_STRS("requestBody")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(THIS_CE, ZEND_STRS("queryData")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(THIS_CE, ZEND_STRS("putFile")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(THIS_CE, ZEND_STRS("putData")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("history")-1, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_bool(THIS_CE, ZEND_STRS("recordHistory")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); - zend_declare_property_string(THIS_CE, ZEND_STRS("messageClass")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC); - -#ifndef WONKY - /* - * Request Method Constants - */ - /* HTTP/1.1 */ - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_GET")-1, HTTP_GET TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_HEAD")-1, HTTP_HEAD TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_POST")-1, HTTP_POST TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_PUT")-1, HTTP_PUT TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_DELETE")-1, HTTP_DELETE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_OPTIONS")-1, HTTP_OPTIONS TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_TRACE")-1, HTTP_TRACE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_CONNECT")-1, HTTP_CONNECT TSRMLS_CC); - /* WebDAV - RFC 2518 */ - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_PROPFIND")-1, HTTP_PROPFIND TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_PROPPATCH")-1, HTTP_PROPPATCH TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MKCOL")-1, HTTP_MKCOL TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_COPY")-1, HTTP_COPY TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MOVE")-1, HTTP_MOVE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_LOCK")-1, HTTP_LOCK TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_UNLOCK")-1, HTTP_UNLOCK TSRMLS_CC); - /* WebDAV Versioning - RFC 3253 */ - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_VERSION_CONTROL")-1, HTTP_VERSION_CONTROL TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_REPORT")-1, HTTP_REPORT TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_CHECKOUT")-1, HTTP_CHECKOUT TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_CHECKIN")-1, HTTP_CHECKIN TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_UNCHECKOUT")-1, HTTP_UNCHECKOUT TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MKWORKSPACE")-1, HTTP_MKWORKSPACE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_UPDATE")-1, HTTP_UPDATE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_LABEL")-1, HTTP_LABEL TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MERGE")-1, HTTP_MERGE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_BASELINE_CONTROL")-1, HTTP_BASELINE_CONTROL TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_MKACTIVITY")-1, HTTP_MKACTIVITY TSRMLS_CC); - /* WebDAV Access Control - RFC 3744 */ - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("METH_ACL")-1, HTTP_ACL TSRMLS_CC); - - /* - * HTTP Protocol Version Constants - */ - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("VERSION_1_0")-1, CURL_HTTP_VERSION_1_0 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("VERSION_1_1")-1, CURL_HTTP_VERSION_1_1 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("VERSION_NONE")-1, CURL_HTTP_VERSION_NONE TSRMLS_CC); /* to be removed */ - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("VERSION_ANY")-1, CURL_HTTP_VERSION_NONE TSRMLS_CC); - - /* - * SSL Version Constants - */ - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("SSL_VERSION_TLSv1")-1, CURL_SSLVERSION_TLSv1 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("SSL_VERSION_SSLv2")-1, CURL_SSLVERSION_SSLv2 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("SSL_VERSION_SSLv3")-1, CURL_SSLVERSION_SSLv3 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("SSL_VERSION_ANY")-1, CURL_SSLVERSION_DEFAULT TSRMLS_CC); - - /* - * DNS IPvX resolving - */ - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("IPRESOLVE_V4")-1, CURL_IPRESOLVE_V4 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("IPRESOLVE_V6")-1, CURL_IPRESOLVE_V6 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("IPRESOLVE_ANY")-1, CURL_IPRESOLVE_WHATEVER TSRMLS_CC); - - /* - * Auth Constants - */ - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_BASIC")-1, CURLAUTH_BASIC TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_DIGEST")-1, CURLAUTH_DIGEST TSRMLS_CC); -#if HTTP_CURL_VERSION(7,19,3) - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_DIGEST_IE")-1, CURLAUTH_DIGEST_IE TSRMLS_CC); -#endif - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_NTLM")-1, CURLAUTH_NTLM TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_GSSNEG")-1, CURLAUTH_GSSNEGOTIATE TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("AUTH_ANY")-1, CURLAUTH_ANY TSRMLS_CC); - - /* - * Proxy Type Constants - */ -# if HTTP_CURL_VERSION(7,15,2) - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_SOCKS4")-1, CURLPROXY_SOCKS4 TSRMLS_CC); -# endif -#if HTTP_CURL_VERSION(7,18,0) - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_SOCKS4A")-1, CURLPROXY_SOCKS5 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_SOCKS5_HOSTNAME")-1, CURLPROXY_SOCKS5 TSRMLS_CC); -#endif - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_SOCKS5")-1, CURLPROXY_SOCKS5 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_HTTP")-1, CURLPROXY_HTTP TSRMLS_CC); -# if HTTP_CURL_VERSION(7,19,4) - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("PROXY_HTTP_1_0")-1, CURLPROXY_HTTP_1_0 TSRMLS_CC); -# endif -#endif /* WONKY */ - - /* - * Post Redirection Constants - */ -#if HTTP_CURL_VERSION(7,19,1) - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("POSTREDIR_301")-1, CURL_REDIR_POST_301 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("POSTREDIR_302")-1, CURL_REDIR_POST_302 TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("POSTREDIR_ALL")-1, CURL_REDIR_POST_ALL TSRMLS_CC); -#endif - - return SUCCESS; -} - -zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return http_request_object_new_ex(ce, NULL, NULL); -} - -zend_object_value _http_request_object_new_ex(zend_class_entry *ce, CURL *ch, http_request_object **ptr TSRMLS_DC) -{ - zend_object_value ov; - http_request_object *o; - - o = ecalloc(1, sizeof(http_request_object)); - o->zo.ce = ce; - o->request = http_request_init_ex(NULL, ch, 0, NULL); - - if (ptr) { - *ptr = o; - } - -#ifdef ZEND_ENGINE_2_4 - zend_object_std_init(o, ce TSRMLS_CC); - object_properties_init(o, ce); -#else - ALLOC_HASHTABLE(OBJ_PROP(o)); - zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); -#endif - - ov.handle = putObject(http_request_object, o); - ov.handlers = &http_request_object_handlers; - - return ov; -} - -zend_object_value _http_request_object_clone_obj(zval *this_ptr TSRMLS_DC) -{ - zend_object_value new_ov; - http_request_object *new_obj; - getObject(http_request_object, old_obj); - - new_ov = http_request_object_new_ex(old_obj->zo.ce, NULL, &new_obj); - if (old_obj->request->ch) { - http_curl_init_ex(http_curl_copy(old_obj->request->ch), new_obj->request); - } - - zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); - phpstr_append(&new_obj->request->conv.request, old_obj->request->conv.request.data, old_obj->request->conv.request.used); - phpstr_append(&new_obj->request->conv.response, old_obj->request->conv.response.data, old_obj->request->conv.response.used); - - return new_ov; -} - -void _http_request_object_free(zend_object *object TSRMLS_DC) -{ - http_request_object *o = (http_request_object *) object; - - http_request_free(&o->request); - freeObject(o); -} - -#define http_request_object_check_request_content_type(t) _http_request_object_check_request_content_type((t) TSRMLS_CC) -static inline void _http_request_object_check_request_content_type(zval *this_ptr TSRMLS_DC) -{ - zval *ctype = zend_read_property(THIS_CE, getThis(), ZEND_STRS("contentType")-1, 0 TSRMLS_CC); - - if (Z_STRLEN_P(ctype)) { - zval **headers, *opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC); - - if ( (Z_TYPE_P(opts) == IS_ARRAY) && - (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void *) &headers)) && - (Z_TYPE_PP(headers) == IS_ARRAY)) { - zval **ct_header; - - /* only override if not already set */ - if ((SUCCESS != zend_hash_find(Z_ARRVAL_PP(headers), "Content-Type", sizeof("Content-Type"), (void *) &ct_header))) { - add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1); - } else - /* or not a string, zero length string or a string of spaces */ - if ((Z_TYPE_PP(ct_header) != IS_STRING) || !Z_STRLEN_PP(ct_header)) { - add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1); - } else { - int i, only_space = 1; - - /* check for spaces only */ - for (i = 0; i < Z_STRLEN_PP(ct_header); ++i) { - if (!HTTP_IS_CTYPE(space, Z_STRVAL_PP(ct_header)[i])) { - only_space = 0; - break; - } - } - if (only_space) { - add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1); - } - } - } else { - zval *headers; - - MAKE_STD_ZVAL(headers); - array_init(headers); - add_assoc_stringl(headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1); - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addheaders", NULL, headers); - zval_ptr_dtor(&headers); - } - } -} - -#define http_request_object_message(zo, msg) _http_request_object_message((zo), (msg) TSRMLS_CC) -static inline zend_object_value _http_request_object_message(zval *this_ptr, http_message *msg TSRMLS_DC) -{ - zend_object_value ov; - zval *zcn = zend_read_property(THIS_CE, getThis(), ZEND_STRS("messageClass")-1, 0 TSRMLS_CC); - - if (Z_STRLEN_P(zcn) && (SUCCESS == http_object_new(&ov, Z_STRVAL_P(zcn), Z_STRLEN_P(zcn), _http_message_object_new_ex, http_message_object_ce, msg, NULL))) { - return ov; - } else { - return http_message_object_new_ex(http_message_object_ce, msg, NULL); - } -} - -STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr TSRMLS_DC) -{ - STATUS status = SUCCESS; - char *url = http_absolute_url(Z_STRVAL_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("url")-1, 0 TSRMLS_CC))); - - if (!url) { - return FAILURE; - } - - http_request_reset(obj->request); - obj->request->url = url; - HTTP_CHECK_CURL_INIT(obj->request->ch, http_curl_init(obj->request), return FAILURE); - - switch (obj->request->meth = Z_LVAL_P(zend_read_property(THIS_CE, getThis(), ZEND_STRS("method")-1, 0 TSRMLS_CC))) - { - case HTTP_GET: - case HTTP_HEAD: - break; - - case HTTP_PUT: - { - zval *put_file = zend_read_property(THIS_CE, getThis(), ZEND_STRS("putFile")-1, 0 TSRMLS_CC); - - http_request_object_check_request_content_type(getThis()); - - if (Z_STRLEN_P(put_file)) { - php_stream_statbuf ssb; - php_stream *stream = php_stream_open_wrapper_ex(Z_STRVAL_P(put_file), "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT); - - if (stream && SUCCESS == php_stream_stat(stream, &ssb)) { - obj->request->body = http_request_body_init_ex(obj->request->body, HTTP_REQUEST_BODY_UPLOADFILE, stream, ssb.sb.st_size, 1); - } else { - status = FAILURE; - } - } else { - zval *put_data = zend_read_property(THIS_CE, getThis(), ZEND_STRS("putData")-1, 0 TSRMLS_CC); - obj->request->body = http_request_body_init_ex(obj->request->body, HTTP_REQUEST_BODY_CSTRING, - estrndup(Z_STRVAL_P(put_data), Z_STRLEN_P(put_data)), Z_STRLEN_P(put_data), 1); - } - break; - } - - case HTTP_POST: - default: - { - /* check for raw request body */ - zval *raw_data = zend_read_property(THIS_CE, getThis(), ZEND_STRS("requestBody")-1, 0 TSRMLS_CC); - - if (Z_STRLEN_P(raw_data)) { - http_request_object_check_request_content_type(getThis()); - obj->request->body = http_request_body_init_ex(obj->request->body, HTTP_REQUEST_BODY_CSTRING, - estrndup(Z_STRVAL_P(raw_data), Z_STRLEN_P(raw_data)), Z_STRLEN_P(raw_data), 1); - } else { - zval *zfields = zend_read_property(THIS_CE, getThis(), ZEND_STRS("postFields")-1, 0 TSRMLS_CC), *zfiles = zend_read_property(THIS_CE, getThis(), ZEND_STRS("postFiles")-1, 0 TSRMLS_CC); - HashTable *fields; - HashTable *files; - - fields = (Z_TYPE_P(zfields) == IS_ARRAY) ? Z_ARRVAL_P(zfields) : NULL; - files = (Z_TYPE_P(zfiles) == IS_ARRAY) ? Z_ARRVAL_P(zfiles) : NULL; - - if ((fields && zend_hash_num_elements(fields)) || (files && zend_hash_num_elements(files))) { - if (!(obj->request->body = http_request_body_fill(obj->request->body, fields, files))) { - status = FAILURE; - } - } - } - break; - } - } - - if (status == SUCCESS) { - zval *qdata = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryData")-1, 0 TSRMLS_CC); - zval *options = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC); - - if (Z_STRLEN_P(qdata)) { - if (!strchr(obj->request->url, '?')) { - strlcat(obj->request->url, "?", HTTP_URL_MAXLEN); - } else { - strlcat(obj->request->url, "&", HTTP_URL_MAXLEN); - } - strlcat(obj->request->url, Z_STRVAL_P(qdata), HTTP_URL_MAXLEN); - } - - http_request_prepare(obj->request, Z_ARRVAL_P(options)); - - /* check if there's a onProgress method and add it as progress callback if one isn't already set */ - if (zend_hash_exists(&Z_OBJCE_P(getThis())->function_table, "onprogress", sizeof("onprogress"))) { - zval **entry, *pcb; - - if ( (Z_TYPE_P(options) != IS_ARRAY) - || (SUCCESS != zend_hash_find(Z_ARRVAL_P(options), "onprogress", sizeof("onprogress"), (void *) &entry) - || (!HTTP_IS_CALLABLE(*entry, 0, NULL)))) { - MAKE_STD_ZVAL(pcb); - array_init(pcb); - ZVAL_ADDREF(getThis()); - add_next_index_zval(pcb, getThis()); - add_next_index_stringl(pcb, "onprogress", lenof("onprogress"), 1); - http_request_set_progress_callback(obj->request, pcb); - zval_ptr_dtor(&pcb); - } - } - } - - return status; -} - -STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this_ptr TSRMLS_DC) -{ - STATUS ret; - zval *info; - http_message *msg; - - /* always fetch info */ - MAKE_STD_ZVAL(info); - array_init(info); - http_request_info(obj->request, Z_ARRVAL_P(info)); - zend_update_property(THIS_CE, getThis(), ZEND_STRS("responseInfo")-1, info TSRMLS_CC); - zval_ptr_dtor(&info); - - /* parse response message */ - phpstr_fix(&obj->request->conv.request); - phpstr_fix(&obj->request->conv.response); - - if ((msg = http_message_parse(PHPSTR_VAL(&obj->request->conv.response), PHPSTR_LEN(&obj->request->conv.response)))) { - zval *message; - - if (i_zend_is_true(zend_read_property(THIS_CE, getThis(), ZEND_STRS("recordHistory")-1, 0 TSRMLS_CC))) { - zval *hist, *history = zend_read_property(THIS_CE, getThis(), ZEND_STRS("history")-1, 0 TSRMLS_CC); - http_message *response = http_message_parse(PHPSTR_VAL(&obj->request->conv.response), PHPSTR_LEN(&obj->request->conv.response)); - http_message *request = http_message_parse(PHPSTR_VAL(&obj->request->conv.request), PHPSTR_LEN(&obj->request->conv.request)); - - MAKE_STD_ZVAL(hist); - ZVAL_OBJVAL(hist, http_request_object_message(getThis(), http_message_interconnect(response, request)), 0); - if (Z_TYPE_P(history) == IS_OBJECT) { - http_message_object_prepend(hist, history); - } - zend_update_property(THIS_CE, getThis(), ZEND_STRS("history")-1, hist TSRMLS_CC); - zval_ptr_dtor(&hist); - } - - zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("responseCode")-1, msg->http.info.response.code TSRMLS_CC); - zend_update_property_string(THIS_CE, getThis(), ZEND_STRS("responseStatus")-1, STR_PTR(msg->http.info.response.status) TSRMLS_CC); - - MAKE_STD_ZVAL(message); - ZVAL_OBJVAL(message, http_request_object_message(getThis(), msg), 0); - zend_update_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, message TSRMLS_CC); - zval_ptr_dtor(&message); - - ret = SUCCESS; - } else { - /* update properties with empty values*/ - zval *znull; - - MAKE_STD_ZVAL(znull); - ZVAL_NULL(znull); - zend_update_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, znull TSRMLS_CC); - zval_ptr_dtor(&znull); - - zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("responseCode")-1, 0 TSRMLS_CC); - zend_update_property_string(THIS_CE, getThis(), ZEND_STRS("responseStatus")-1, "" TSRMLS_CC); - - /* append request message to history */ - if (i_zend_is_true(zend_read_property(THIS_CE, getThis(), ZEND_STRS("recordHistory")-1, 0 TSRMLS_CC))) { - http_message *request; - - if ((request = http_message_parse(PHPSTR_VAL(&obj->request->conv.request), PHPSTR_LEN(&obj->request->conv.request)))) { - zval *hist, *history = zend_read_property(THIS_CE, getThis(), ZEND_STRS("history")-1, 0 TSRMLS_CC); - - MAKE_STD_ZVAL(hist); - ZVAL_OBJVAL(hist, http_request_object_message(getThis(), request), 0); - if (Z_TYPE_P(history) == IS_OBJECT) { - http_message_object_prepend(hist, history); - } - zend_update_property(THIS_CE, getThis(), ZEND_STRS("history")-1, hist TSRMLS_CC); - zval_ptr_dtor(&hist); - } - } - - ret = FAILURE; - } - - http_request_set_progress_callback(obj->request, NULL); - - if (!EG(exception) && zend_hash_exists(&Z_OBJCE_P(getThis())->function_table, "onfinish", sizeof("onfinish"))) { - zval *param; - - MAKE_STD_ZVAL(param); - ZVAL_BOOL(param, ret == SUCCESS); - with_error_handling(EH_NORMAL, NULL) { - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "onfinish", NULL, param); - } end_error_handling(); - zval_ptr_dtor(¶m); - } - - return ret; -} -#ifdef ZEND_ENGINE_2_4 -# define APK_DC TSRMLS_DC -#else -# define APK_DC -#endif -static int apply_pretty_key(void *pDest APK_DC, int num_args, va_list args, zend_hash_key *hash_key) -{ - if (hash_key->arKey && hash_key->nKeyLength > 1) { - hash_key->h = zend_hash_func(pretty_key(hash_key->arKey, hash_key->nKeyLength - 1, 1, 0), hash_key->nKeyLength); - } - return ZEND_HASH_APPLY_KEEP; -} - -#define http_request_object_set_options_subr(key, ow, pk) \ - _http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, (key), sizeof(key), (ow), (pk)) -static inline void _http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len, int overwrite, int prettify_keys) -{ - zval *old_opts, *new_opts, *opts = NULL, **entry = NULL; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &opts)) { - RETURN_FALSE; - } - - MAKE_STD_ZVAL(new_opts); - array_init(new_opts); - old_opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC); - if (Z_TYPE_P(old_opts) == IS_ARRAY) { - array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); - } - - if (SUCCESS == zend_hash_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) { - if (overwrite) { - zend_hash_clean(Z_ARRVAL_PP(entry)); - } - if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { - if (overwrite) { - array_copy(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry)); - } else { - array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, prettify_keys ? ARRAY_JOIN_PRETTIFY : 0); - } - } - } else if (opts) { - if (prettify_keys) { - zend_hash_apply_with_arguments(Z_ARRVAL_P(opts) HTTP_ZAPI_HASH_TSRMLS_CC, apply_pretty_key, 0, NULL); - } - ZVAL_ADDREF(opts); - add_assoc_zval_ex(new_opts, key, len, opts); - } - zend_update_property(THIS_CE, getThis(), ZEND_STRS("options")-1, new_opts TSRMLS_CC); - zval_ptr_dtor(&new_opts); - - RETURN_TRUE; -} - -#define http_request_object_get_options_subr(key) \ - _http_request_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, (key), sizeof(key)) -static inline void _http_request_get_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len) -{ - NO_ARGS; - - if (return_value_used) { - zval *opts, **options; - - opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC); - array_init(return_value); - - if ( (Z_TYPE_P(opts) == IS_ARRAY) && - (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) { - convert_to_array(*options); - array_copy(Z_ARRVAL_PP(options), Z_ARRVAL_P(return_value)); - } - } -} - - -/* ### USERLAND ### */ - -/* {{{ proto void HttpRequest::__construct([string url[, int request_method = HTTP_METH_GET[, array options]]]) - Create a new HttpRequest object instance. */ -PHP_METHOD(HttpRequest, __construct) -{ - char *URL = NULL; - int URL_len; - long meth = -1; - zval *options = NULL; - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sla!", &URL, &URL_len, &meth, &options)) { - if (URL) { - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("url")-1, URL, URL_len TSRMLS_CC); - } - if (meth > -1) { - zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("method")-1, meth TSRMLS_CC); - } - if (options) { - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setoptions", NULL, options); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto HttpRequest HttpRequest::factory([string url[, int request_method HTTP_METH_GET[, array options[, string class_name = "HttpRequest"]]]]) - Create a new HttpRequest object instance. */ -PHP_METHOD(HttpRequest, factory) -{ - char *cn = NULL, *URL = NULL; - int cl = 0, URL_len = 0; - long meth = -1; - zval *options = NULL; - zend_object_value ov; - - SET_EH_THROW_HTTP(); - if ( SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sla!s", &URL, &URL_len, &meth, &options, &cn, &cl) && - SUCCESS == http_object_new(&ov, cn, cl, _http_request_object_new_ex, http_request_object_ce, NULL, NULL)) { - RETVAL_OBJVAL(ov, 0); - getThis() = return_value; - if (URL) { - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("url")-1, URL, URL_len TSRMLS_CC); - } - if (meth > -1) { - zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("method")-1, meth TSRMLS_CC); - } - if (options) { - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setoptions", NULL, options); - } - } - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setOptions([array options]) - Set the request options to use. See http_get() for a full list of available options. */ -PHP_METHOD(HttpRequest, setOptions) -{ - HashKey key = initHashKey(0); - HashPosition pos; - zval *opts = NULL, *old_opts, *new_opts, *add_opts, **opt; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { - RETURN_FALSE; - } - - MAKE_STD_ZVAL(new_opts); - array_init(new_opts); - - if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) { - zend_update_property(THIS_CE, getThis(), ZEND_STRS("options")-1, new_opts TSRMLS_CC); - zval_ptr_dtor(&new_opts); - RETURN_TRUE; - } - - MAKE_STD_ZVAL(add_opts); - array_init(add_opts); - /* some options need extra attention -- thus cannot use array_merge() directly */ - FOREACH_KEYVAL(pos, opts, key, opt) { - if (key.type == HASH_KEY_IS_STRING) { -#define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s)) - if (KEYMATCH(key, "headers")) { - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addheaders", NULL, *opt); - } else if (KEYMATCH(key, "cookies")) { - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addcookies", NULL, *opt); - } else if (KEYMATCH(key, "ssl")) { - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addssloptions", NULL, *opt); - } else if (KEYMATCH(key, "url") || KEYMATCH(key, "uri")) { - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "seturl", NULL, *opt); - } else if (KEYMATCH(key, "method")) { - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setmethod", NULL, *opt); - } else if (KEYMATCH(key, "flushcookies")) { - getObject(http_request_object, obj); - if (i_zend_is_true(*opt)) { - http_request_flush_cookies(obj->request); - } - } else if (KEYMATCH(key, "resetcookies")) { - getObject(http_request_object, obj); - http_request_reset_cookies(obj->request, (zend_bool) i_zend_is_true(*opt)); - } else if (KEYMATCH(key, "enablecookies")) { - getObject(http_request_object, obj); - http_request_enable_cookies(obj->request); - } else if (KEYMATCH(key, "recordHistory")) { - zend_update_property(THIS_CE, getThis(), ZEND_STRS("recordHistory")-1, *opt TSRMLS_CC); - } else if (KEYMATCH(key, "messageClass")) { - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setmessageclass", NULL, *opt); - } else if (Z_TYPE_PP(opt) == IS_NULL) { - old_opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC); - if (Z_TYPE_P(old_opts) == IS_ARRAY) { - zend_hash_del(Z_ARRVAL_P(old_opts), key.str, key.len); - } - } else { - ZVAL_ADDREF(*opt); - add_assoc_zval_ex(add_opts, key.str, key.len, *opt); - } - } - } - - old_opts = zend_read_property(THIS_CE, getThis(), ZEND_STRS("options")-1, 0 TSRMLS_CC); - if (Z_TYPE_P(old_opts) == IS_ARRAY) { - array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); - } - array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0); - zend_update_property(THIS_CE, getThis(), ZEND_STRS("options")-1, new_opts TSRMLS_CC); - zval_ptr_dtor(&new_opts); - zval_ptr_dtor(&add_opts); - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto array HttpRequest::getOptions() - Get currently set options. */ -PHP_METHOD(HttpRequest, getOptions) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(options); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setSslOptions([array options]) - Set SSL options. */ -PHP_METHOD(HttpRequest, setSslOptions) -{ - http_request_object_set_options_subr("ssl", 1, 0); -} -/* }}} */ - -/* {{{ proto bool HttpRequest::addSslOptions(array options) - Set additional SSL options. */ -PHP_METHOD(HttpRequest, addSslOptions) -{ - http_request_object_set_options_subr("ssl", 0, 0); -} -/* }}} */ - -/* {{{ proto array HttpRequest::getSslOtpions() - Get previously set SSL options. */ -PHP_METHOD(HttpRequest, getSslOptions) -{ - http_request_object_get_options_subr("ssl"); -} -/* }}} */ - -/* {{{ proto bool HttpRequest::addHeaders(array headers) - Add request header name/value pairs. */ -PHP_METHOD(HttpRequest, addHeaders) -{ - http_request_object_set_options_subr("headers", 0, 1); -} - -/* {{{ proto bool HttpRequest::setHeaders([array headers]) - Set request header name/value pairs. */ -PHP_METHOD(HttpRequest, setHeaders) -{ - http_request_object_set_options_subr("headers", 1, 1); -} -/* }}} */ - -/* {{{ proto array HttpRequest::getHeaders() - Get previously set request headers. */ -PHP_METHOD(HttpRequest, getHeaders) -{ - http_request_object_get_options_subr("headers"); -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setCookies([array cookies]) - Set cookies. */ -PHP_METHOD(HttpRequest, setCookies) -{ - http_request_object_set_options_subr("cookies", 1, 0); -} -/* }}} */ - -/* {{{ proto bool HttpRequest::addCookies(array cookies) - Add cookies. */ -PHP_METHOD(HttpRequest, addCookies) -{ - http_request_object_set_options_subr("cookies", 0, 0); -} -/* }}} */ - -/* {{{ proto array HttpRequest::getCookies() - Get previously set cookies. */ -PHP_METHOD(HttpRequest, getCookies) -{ - http_request_object_get_options_subr("cookies"); -} -/* }}} */ - -/* {{{ proto bool HttpRequest::enableCookies() - Enable automatic sending of received cookies. Note that customly set cookies will be sent anyway. */ -PHP_METHOD(HttpRequest, enableCookies) -{ - NO_ARGS { - getObject(http_request_object, obj); - RETURN_SUCCESS(http_request_enable_cookies(obj->request)); - } - -} -/* }}} */ - -/* {{{ proto bool HttpRequest::resetCookies([bool session_only = FALSE]) - Reset all automatically received/sent cookies. Note that customly set cookies are not affected. */ -PHP_METHOD(HttpRequest, resetCookies) -{ - zend_bool session_only = 0; - getObject(http_request_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &session_only)) { - RETURN_FALSE; - } - RETURN_SUCCESS(http_request_reset_cookies(obj->request, session_only)); -} -/* }}} */ - -/* {{{ proto bool HttpRequest::flushCookies() - Flush internal cookies to the cookiestore file */ -PHP_METHOD(HttpRequest, flushCookies) -{ - NO_ARGS { - getObject(http_request_object, obj); - RETURN_SUCCESS(http_request_flush_cookies(obj->request)); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setUrl(string url) - Set the request URL. */ -PHP_METHOD(HttpRequest, setUrl) -{ - char *URL = NULL; - int URL_len; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) { - RETURN_FALSE; - } - - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("url")-1, URL, URL_len TSRMLS_CC); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpRequest::getUrl() - Get the previously set request URL. */ -PHP_METHOD(HttpRequest, getUrl) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(url); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setMethod(int request_method) - Set the request method. */ -PHP_METHOD(HttpRequest, setMethod) -{ - long meth; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) { - RETURN_FALSE; - } - - zend_update_property_long(THIS_CE, getThis(), ZEND_STRS("method")-1, meth TSRMLS_CC); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto int HttpRequest::getMethod() - Get the previously set request method. */ -PHP_METHOD(HttpRequest, getMethod) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(method); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setContentType(string content_type) - Set the content type the post request should have. */ -PHP_METHOD(HttpRequest, setContentType) -{ - char *ctype; - int ct_len; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) { - RETURN_FALSE; - } - - if (ct_len) { - HTTP_CHECK_CONTENT_TYPE(ctype, RETURN_FALSE); - } - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("contentType")-1, ctype, ct_len TSRMLS_CC); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpRequest::getContentType() - Get the previously content type. */ -PHP_METHOD(HttpRequest, getContentType) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(contentType); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setQueryData([mixed query_data]) - Set the URL query parameters to use, overwriting previously set query parameters. */ -PHP_METHOD(HttpRequest, setQueryData) -{ - zval *qdata = NULL; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!", &qdata)) { - RETURN_FALSE; - } - - if ((!qdata) || Z_TYPE_P(qdata) == IS_NULL) { - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("queryData")-1, "", 0 TSRMLS_CC); - } else if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) { - char *query_data = NULL; - - if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) { - RETURN_FALSE; - } - - zend_update_property_string(THIS_CE, getThis(), ZEND_STRS("queryData")-1, query_data TSRMLS_CC); - efree(query_data); - } else { - zval *data = http_zsep(IS_STRING, qdata); - - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("queryData")-1, Z_STRVAL_P(data), Z_STRLEN_P(data) TSRMLS_CC); - zval_ptr_dtor(&data); - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpRequest::getQueryData() - Get the current query data in form of an urlencoded query string. */ -PHP_METHOD(HttpRequest, getQueryData) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(queryData); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::addQueryData(array query_params) - Add parameters to the query parameter list, leaving previously set unchanged. */ -PHP_METHOD(HttpRequest, addQueryData) -{ - zval *qdata, *old_qdata; - char *query_data = NULL; - size_t query_data_len = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &qdata)) { - RETURN_FALSE; - } - - old_qdata = zend_read_property(THIS_CE, getThis(), ZEND_STRS("queryData")-1, 0 TSRMLS_CC); - - if (SUCCESS != http_urlencode_hash_ex(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data, &query_data_len)) { - RETURN_FALSE; - } - - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("queryData")-1, query_data, query_data_len TSRMLS_CC); - efree(query_data); - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool HttpRequest::addPostFields(array post_data) - Adds POST data entries, leaving previously set unchanged, unless a post entry with the same name already exists. */ -PHP_METHOD(HttpRequest, addPostFields) -{ - zval *post_data, *old_post, *new_post; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &post_data)) { - RETURN_FALSE; - } - - if (zend_hash_num_elements(Z_ARRVAL_P(post_data))) { - MAKE_STD_ZVAL(new_post); - array_init(new_post); - old_post = zend_read_property(THIS_CE, getThis(), ZEND_STRS("postFields")-1, 0 TSRMLS_CC); - if (Z_TYPE_P(old_post) == IS_ARRAY) { - array_copy(Z_ARRVAL_P(old_post), Z_ARRVAL_P(new_post)); - } - array_join(Z_ARRVAL_P(post_data), Z_ARRVAL_P(new_post), 0, 0); - zend_update_property(THIS_CE, getThis(), ZEND_STRS("postFields")-1, new_post TSRMLS_CC); - zval_ptr_dtor(&new_post); - } - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setPostFields([array post_data]) - Set the POST data entries, overwriting previously set POST data. */ -PHP_METHOD(HttpRequest, setPostFields) -{ - zval *post, *post_data = NULL; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &post_data)) { - RETURN_FALSE; - } - - MAKE_STD_ZVAL(post); - array_init(post); - if (post_data && zend_hash_num_elements(Z_ARRVAL_P(post_data))) { - array_copy(Z_ARRVAL_P(post_data), Z_ARRVAL_P(post)); - } - zend_update_property(THIS_CE, getThis(), ZEND_STRS("postFields")-1, post TSRMLS_CC); - zval_ptr_dtor(&post); - - RETURN_TRUE; -} -/* }}}*/ - -/* {{{ proto array HttpRequest::getPostFields() - Get previously set POST data. */ -PHP_METHOD(HttpRequest, getPostFields) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(postFields); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setBody([string request_body_data]) - Set request body to send, overwriting previously set request body. Don't forget to specify a content type. */ -PHP_METHOD(HttpRequest, setBody) -{ - char *raw_data = NULL; - int data_len = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &raw_data, &data_len)) { - RETURN_FALSE; - } - - if (!raw_data) { - raw_data = ""; - } - - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("requestBody")-1, raw_data, data_len TSRMLS_CC); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool HttpRequest::addBody(string request_body_data) - Add request body data, leaving previously set request body data unchanged. */ -PHP_METHOD(HttpRequest, addBody) -{ - char *raw_data; - int data_len; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &raw_data, &data_len)) { - RETURN_FALSE; - } - - if (data_len) { - zval *data = zend_read_property(THIS_CE, getThis(), ZEND_STRS("requestBody")-1, 0 TSRMLS_CC); - - if (Z_STRLEN_P(data)) { - Z_STRVAL_P(data) = erealloc(Z_STRVAL_P(data), (Z_STRLEN_P(data) += data_len) + 1); - Z_STRVAL_P(data)[Z_STRLEN_P(data)] = '\0'; - memcpy(Z_STRVAL_P(data) + Z_STRLEN_P(data) - data_len, raw_data, data_len); - } else { - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("requestBody")-1, raw_data, data_len TSRMLS_CC); - } - } - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpRequest::getBody() - Get previously set request body data. */ -PHP_METHOD(HttpRequest, getBody) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(requestBody); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"]) - Add a file to the POST request, leaving previously set files unchanged. */ -PHP_METHOD(HttpRequest, addPostFile) -{ - zval *entry, *old_post, *new_post; - char *name, *file, *type = NULL; - int name_len, file_len, type_len = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) { - RETURN_FALSE; - } - - if (type_len) { - HTTP_CHECK_CONTENT_TYPE(type, RETURN_FALSE); - } else { - type = "application/x-octetstream"; - type_len = sizeof("application/x-octetstream") - 1; - } - - MAKE_STD_ZVAL(entry); - array_init(entry); - - add_assoc_stringl(entry, "name", name, name_len, 1); - add_assoc_stringl(entry, "type", type, type_len, 1); - add_assoc_stringl(entry, "file", file, file_len, 1); - - MAKE_STD_ZVAL(new_post); - array_init(new_post); - old_post = zend_read_property(THIS_CE, getThis(), ZEND_STRS("postFiles")-1, 0 TSRMLS_CC); - if (Z_TYPE_P(old_post) == IS_ARRAY) { - array_copy(Z_ARRVAL_P(old_post), Z_ARRVAL_P(new_post)); - } - add_next_index_zval(new_post, entry); - zend_update_property(THIS_CE, getThis(), ZEND_STRS("postFiles")-1, new_post TSRMLS_CC); - zval_ptr_dtor(&new_post); - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setPostFiles([array post_files]) - Set files to post, overwriting previously set post files. */ -PHP_METHOD(HttpRequest, setPostFiles) -{ - zval *files = NULL, *post; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!/", &files)) { - RETURN_FALSE; - } - - MAKE_STD_ZVAL(post); - array_init(post); - if (files && (Z_TYPE_P(files) == IS_ARRAY)) { - array_copy(Z_ARRVAL_P(files), Z_ARRVAL_P(post)); - } - zend_update_property(THIS_CE, getThis(), ZEND_STRS("postFiles")-1, post TSRMLS_CC); - zval_ptr_dtor(&post); - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto array HttpRequest::getPostFiles() - Get all previously added POST files. */ -PHP_METHOD(HttpRequest, getPostFiles) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(postFiles); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setPutFile([string file]) - Set file to put. Affects only PUT requests. */ -PHP_METHOD(HttpRequest, setPutFile) -{ - char *file = ""; - int file_len = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &file, &file_len)) { - RETURN_FALSE; - } - - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("putFile")-1, file, file_len TSRMLS_CC); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpRequest::getPutFile() - Get previously set put file. */ -PHP_METHOD(HttpRequest, getPutFile) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(putFile); - } -} -/* }}} */ - -/* {{{ proto bool HttpRequest::setPutData([string put_data]) - Set PUT data to send, overwriting previously set PUT data. */ -PHP_METHOD(HttpRequest, setPutData) -{ - char *put_data = NULL; - int data_len = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &put_data, &data_len)) { - RETURN_FALSE; - } - - if (!put_data) { - put_data = ""; - } - - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("putData")-1, put_data, data_len TSRMLS_CC); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool HttpRequest::addPutData(string put_data) - Add PUT data, leaving previously set PUT data unchanged. */ -PHP_METHOD(HttpRequest, addPutData) -{ - char *put_data; - int data_len; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &put_data, &data_len)) { - RETURN_FALSE; - } - - if (data_len) { - zval *data = zend_read_property(THIS_CE, getThis(), ZEND_STRS("putData")-1, 0 TSRMLS_CC); - - if (Z_STRLEN_P(data)) { - Z_STRVAL_P(data) = erealloc(Z_STRVAL_P(data), (Z_STRLEN_P(data) += data_len) + 1); - Z_STRVAL_P(data)[Z_STRLEN_P(data)] = '\0'; - memcpy(Z_STRVAL_P(data) + Z_STRLEN_P(data) - data_len, put_data, data_len); - } else { - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("putData")-1, put_data, data_len TSRMLS_CC); - } - } - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto string HttpRequest::getPutData() - Get previously set PUT data. */ -PHP_METHOD(HttpRequest, getPutData) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(putData); - } -} -/* }}} */ - -/* {{{ proto array HttpRequest::getResponseData() - Get all response data after the request has been sent. */ -PHP_METHOD(HttpRequest, getResponseData) -{ - NO_ARGS; - - if (return_value_used) { - char *body; - size_t body_len; - zval *headers, *message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC); - - if (Z_TYPE_P(message) == IS_OBJECT) { - getObjectEx(http_message_object, msg, message); - - array_init(return_value); - - MAKE_STD_ZVAL(headers); - array_init(headers); - zend_hash_copy(Z_ARRVAL_P(headers), &msg->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - add_assoc_zval(return_value, "headers", headers); - - phpstr_data(PHPSTR(msg->message), &body, &body_len); - add_assoc_stringl(return_value, "body", body, body_len, 0); - } - } -} -/* }}} */ - -/* {{{ proto mixed HttpRequest::getResponseHeader([string name]) - Get response header(s) after the request has been sent. */ -PHP_METHOD(HttpRequest, getResponseHeader) -{ - if (return_value_used) { - zval *header; - char *header_name = NULL; - int header_len = 0; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) { - zval *message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC); - - if (Z_TYPE_P(message) == IS_OBJECT) { - getObjectEx(http_message_object, msg, message); - - if (header_len) { - if ((header = http_message_header_ex(msg->message, pretty_key(header_name, header_len, 1, 1), header_len + 1, 0))) { - RETURN_ZVAL(header, 1, 1); - } - } else { - array_init(return_value); - zend_hash_copy(Z_ARRVAL_P(return_value), &msg->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - return; - } - } - } - RETURN_FALSE; - } -} -/* }}} */ - -/* {{{ proto array HttpRequest::getResponseCookies([int flags[, array allowed_extras]]) - Get response cookie(s) after the request has been sent. */ -PHP_METHOD(HttpRequest, getResponseCookies) -{ - if (return_value_used) { - long flags = 0; - zval *allowed_extras_array = NULL; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|la!", &flags, &allowed_extras_array)) { - int i = 0; - HashKey key = initHashKey(0); - char **allowed_extras = NULL; - zval **header = NULL, **entry = NULL, *message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC); - HashPosition pos, pos1, pos2; - - if (Z_TYPE_P(message) == IS_OBJECT) { - getObjectEx(http_message_object, msg, message); - - array_init(return_value); - - if (allowed_extras_array) { - allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *)); - FOREACH_VAL(pos, allowed_extras_array, entry) { - zval *data = http_zsep(IS_STRING, *entry); - allowed_extras[i++] = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data)); - zval_ptr_dtor(&data); - } - } - - FOREACH_HASH_KEYVAL(pos1, &msg->message->hdrs, key, header) { - if (key.type == HASH_KEY_IS_STRING && !strcasecmp(key.str, "Set-Cookie")) { - http_cookie_list list; - - if (Z_TYPE_PP(header) == IS_ARRAY) { - zval **single_header; - - FOREACH_VAL(pos2, *header, single_header) { - zval *data = http_zsep(IS_STRING, *single_header); - - if (http_parse_cookie_ex(&list, Z_STRVAL_P(data), flags, allowed_extras)) { - zval *cookie; - - MAKE_STD_ZVAL(cookie); - object_init(cookie); - http_cookie_list_tostruct(&list, cookie); - add_next_index_zval(return_value, cookie); - http_cookie_list_dtor(&list); - } - zval_ptr_dtor(&data); - } - } else { - zval *data = http_zsep(IS_STRING, *header); - if (http_parse_cookie_ex(&list, Z_STRVAL_P(data), flags, allowed_extras)) { - zval *cookie; - - MAKE_STD_ZVAL(cookie); - object_init(cookie); - http_cookie_list_tostruct(&list, cookie); - add_next_index_zval(return_value, cookie); - http_cookie_list_dtor(&list); - } - zval_ptr_dtor(&data); - } - } - } - - if (allowed_extras) { - for (i = 0; allowed_extras[i]; ++i) { - efree(allowed_extras[i]); - } - efree(allowed_extras); - } - - return; - } - } - RETURN_FALSE; - } -} -/* }}} */ - -/* {{{ proto string HttpRequest::getResponseBody() - Get the response body after the request has been sent. */ -PHP_METHOD(HttpRequest, getResponseBody) -{ - NO_ARGS; - - if (return_value_used) { - zval *message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC); - - if (Z_TYPE_P(message) == IS_OBJECT) { - getObjectEx(http_message_object, msg, message); - RETURN_PHPSTR_DUP(&msg->message->body); - } else { - RETURN_FALSE; - } - } -} -/* }}} */ - -/* {{{ proto int HttpRequest::getResponseCode() - Get the response code after the request has been sent. */ -PHP_METHOD(HttpRequest, getResponseCode) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(responseCode); - } -} -/* }}} */ - -/* {{{ proto string HttpRequest::getResponseStatus() - Get the response status (i.e. the string after the response code) after the message has been sent. */ -PHP_METHOD(HttpRequest, getResponseStatus) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP(responseStatus); - } -} -/* }}} */ - -/* {{{ proto mixed HttpRequest::getResponseInfo([string name]) - Get response info after the request has been sent. */ -PHP_METHOD(HttpRequest, getResponseInfo) -{ - if (return_value_used) { - zval *info, **infop; - char *info_name = NULL; - int info_len = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) { - RETURN_FALSE; - } - - info = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseInfo")-1, 0 TSRMLS_CC); - - if (Z_TYPE_P(info) != IS_ARRAY) { - RETURN_FALSE; - } - - if (info_len && info_name) { - if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void *) &infop)) { - RETURN_ZVAL(*infop, 1, 0); - } else { - http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Could not find response info named %s", info_name); - RETURN_FALSE; - } - } else { - RETURN_ZVAL(info, 1, 0); - } - } -} -/* }}}*/ - -/* {{{ proto HttpMessage HttpRequest::getResponseMessage() - Get the full response as HttpMessage object after the request has been sent. */ -PHP_METHOD(HttpRequest, getResponseMessage) -{ - NO_ARGS { - zval *message; - - SET_EH_THROW_HTTP(); - message = zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC); - if (Z_TYPE_P(message) == IS_OBJECT) { - RETVAL_OBJECT(message, 1); - } else { - http_error(HE_WARNING, HTTP_E_RUNTIME, "HttpRequest does not contain a response message"); - } - SET_EH_NORMAL(); - } -} -/* }}} */ - -/* {{{ proto HttpMessage HttpRequest::getRequestMessage() - Get sent HTTP message. */ -PHP_METHOD(HttpRequest, getRequestMessage) -{ - NO_ARGS; - - if (return_value_used) { - http_message *msg; - getObject(http_request_object, obj); - - SET_EH_THROW_HTTP(); - if ((msg = http_message_parse(PHPSTR_VAL(&obj->request->conv.request), PHPSTR_LEN(&obj->request->conv.request)))) { - RETVAL_OBJVAL(http_request_object_message(getThis(), msg), 0); - } - SET_EH_NORMAL(); - } -} -/* }}} */ - -/* {{{ proto string HttpRequest::getRawRequestMessage() - Get sent HTTP message. */ -PHP_METHOD(HttpRequest, getRawRequestMessage) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_request_object, obj); - - RETURN_PHPSTR_DUP(&obj->request->conv.request); - } -} -/* }}} */ - -/* {{{ proto string HttpRequest::getRawResponseMessage() - Get the entire HTTP response. */ -PHP_METHOD(HttpRequest, getRawResponseMessage) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_request_object, obj); - - RETURN_PHPSTR_DUP(&obj->request->conv.response); - } -} -/* }}} */ - -/* {{{ proto HttpMessage HttpRequest::getHistory() - Get all sent requests and received responses as an HttpMessage object. */ -PHP_METHOD(HttpRequest, getHistory) -{ - NO_ARGS; - - if (return_value_used) { - zval *hist; - - SET_EH_THROW_HTTP(); - hist = zend_read_property(THIS_CE, getThis(), ZEND_STRS("history")-1, 0 TSRMLS_CC); - if (Z_TYPE_P(hist) == IS_OBJECT) { - RETVAL_OBJECT(hist, 1); - } else { - http_error(HE_WARNING, HTTP_E_RUNTIME, "The history is empty"); - } - SET_EH_NORMAL(); - } -} -/* }}} */ - -/* {{{ proto void HttpRequest::clearHistory() - Clear the history. */ -PHP_METHOD(HttpRequest, clearHistory) -{ - NO_ARGS { - zval *hist; - - MAKE_STD_ZVAL(hist); - ZVAL_NULL(hist); - zend_update_property(THIS_CE, getThis(), ZEND_STRS("history")-1, hist TSRMLS_CC); - zval_ptr_dtor(&hist); - } -} -/* }}} */ - -/* {{{ proto string HttpRequest::getMessageClass() - Get the message class name. */ -PHP_METHOD(HttpRequest, getMessageClass) -{ - NO_ARGS; - - if (return_value_used) { - RETURN_PROP("messageClass"); - } -} -/* }}} */ - -/* {{{ proto void setMessageClass(string class_name) - Set the message class name. */ -PHP_METHOD(HttpRequest, setMessageClass) -{ - char *cn; - int cl; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cn, &cl)) { - zend_update_property_stringl(THIS_CE, getThis(), ZEND_STRS("messageClass")-1, cn, cl TSRMLS_CC); - } -} -/* }}} */ - -/* {{{ proto HttpMessage HttpRequest::send() - Send the HTTP request. */ -PHP_METHOD(HttpRequest, send) -{ - getObject(http_request_object, obj); - - NO_ARGS; - - SET_EH_THROW_HTTP(); - - RETVAL_FALSE; - - if (obj->pool) { - http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot perform HttpRequest::send() while attached to an HttpRequestPool"); - } else if (SUCCESS == http_request_object_requesthandler(obj, getThis())) { - http_request_exec(obj->request); - if (SUCCESS == http_request_object_responsehandler(obj, getThis())) { - RETVAL_OBJECT(zend_read_property(THIS_CE, getThis(), ZEND_STRS("responseMessage")-1, 0 TSRMLS_CC), 1); - } - } - - SET_EH_NORMAL(); -} -/* }}} */ - -#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_request_pool_api.c b/http_request_pool_api.c deleted file mode 100644 index 04acb2e..0000000 --- a/http_request_pool_api.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_CURL -#define HTTP_WANT_EVENT -#include "php_http.h" - -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) - -#include "php_http_api.h" -#include "php_http_exception_object.h" -#include "php_http_persistent_handle_api.h" -#include "php_http_request_api.h" -#include "php_http_request_object.h" -#include "php_http_request_pool_api.h" -#include "php_http_requestpool_object.h" - -#ifndef HTTP_DEBUG_REQPOOLS -# define HTTP_DEBUG_REQPOOLS 0 -#endif - -#ifdef HTTP_HAVE_EVENT -typedef struct _http_request_pool_event_t { - struct event evnt; - http_request_pool *pool; -} http_request_pool_event; - -static void http_request_pool_timeout_callback(int socket, short action, void *event_data); -static void http_request_pool_event_callback(int socket, short action, void *event_data); -static int http_request_pool_socket_callback(CURL *easy, curl_socket_t s, int action, void *, void *); -static void http_request_pool_timer_callback(CURLM *multi, long timeout_ms, void *timer_data); -#endif - -static int http_request_pool_compare_handles(void *h1, void *h2); - -PHP_MINIT_FUNCTION(http_request_pool) -{ - if (SUCCESS != http_persistent_handle_provide("http_request_pool", curl_multi_init, (http_persistent_handle_dtor) curl_multi_cleanup, NULL)) { - return FAILURE; - } - return SUCCESS; -} - -#ifdef HTTP_HAVE_EVENT -PHP_RINIT_FUNCTION(http_request_pool) -{ - if (!HTTP_G->request.pool.event.base && !(HTTP_G->request.pool.event.base = event_init())) { - return FAILURE; - } - - return SUCCESS; -} -#endif - -/* {{{ http_request_pool *http_request_pool_init(http_request_pool *) */ -PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC) -{ - zend_bool free_pool; - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Initializing request pool %p\n", pool); -#endif - - if ((free_pool = (!pool))) { - pool = emalloc(sizeof(http_request_pool)); - pool->ch = NULL; - } - - if (SUCCESS != http_persistent_handle_acquire("http_request_pool", &pool->ch)) { - if (free_pool) { - efree(pool); - } - return NULL; - } - - TSRMLS_SET_CTX(pool->tsrm_ls); - -#ifdef HTTP_HAVE_EVENT - pool->timeout = ecalloc(1, sizeof(struct event)); - curl_multi_setopt(pool->ch, CURLMOPT_SOCKETDATA, pool); - curl_multi_setopt(pool->ch, CURLMOPT_SOCKETFUNCTION, http_request_pool_socket_callback); - curl_multi_setopt(pool->ch, CURLMOPT_TIMERDATA, pool); - curl_multi_setopt(pool->ch, CURLMOPT_TIMERFUNCTION, http_request_pool_timer_callback); -#endif - - pool->unfinished = 0; - zend_llist_init(&pool->finished, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0); - zend_llist_init(&pool->handles, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0); - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Initialized request pool %p\n", pool); -#endif - - return pool; -} -/* }}} */ - -/* {{{ STATUS http_request_pool_attach(http_request_pool *, zval *) */ -PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request) -{ -#ifdef ZTS - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); -#endif - getObjectEx(http_request_object, req, request); - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Attaching HttpRequest(#%d) %p to pool %p\n", Z_OBJ_HANDLE_P(request), req, pool); -#endif - - if (req->pool) { - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "HttpRequest object(#%d) is already member of %s HttpRequestPool", Z_OBJ_HANDLE_P(request), req->pool == pool ? "this" : "another"); - } else if (SUCCESS != http_request_object_requesthandler(req, request)) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not initialize HttpRequest object(#%d) for attaching to the HttpRequestPool", Z_OBJ_HANDLE_P(request)); - } else { - CURLMcode code = curl_multi_add_handle(pool->ch, req->request->ch); - - if (CURLM_OK != code) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_POOL, "Could not attach HttpRequest object(#%d) to the HttpRequestPool: %s", Z_OBJ_HANDLE_P(request), curl_multi_strerror(code)); - } else { - req->pool = pool; - - ZVAL_ADDREF(request); - zend_llist_add_element(&pool->handles, &request); - ++pool->unfinished; - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "> %d HttpRequests attached to pool %p\n", zend_llist_count(&pool->handles), pool); -#endif - return SUCCESS; - } - } - return FAILURE; -} -/* }}} */ - -/* {{{ STATUS http_request_pool_detach(http_request_pool *, zval *) */ -PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request) -{ - CURLMcode code; -#ifdef ZTS - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); -#endif - getObjectEx(http_request_object, req, request); - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Detaching HttpRequest(#%d) %p from pool %p\n", Z_OBJ_HANDLE_P(request), req, pool); -#endif - - if (!req->pool) { - /* not attached to any pool */ -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "HttpRequest object(#%d) %p is not attached to any HttpRequestPool\n", Z_OBJ_HANDLE_P(request), req); -#endif - } else if (req->pool != pool) { - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "HttpRequest object(#%d) is not attached to this HttpRequestPool", Z_OBJ_HANDLE_P(request)); - } else if (req->request->_in_progress_cb) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_POOL, "HttpRequest object(#%d) cannot be detached from the HttpRequestPool while executing the progress callback", Z_OBJ_HANDLE_P(request)); - } else if (CURLM_OK != (code = curl_multi_remove_handle(pool->ch, req->request->ch))) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_POOL, "Could not detach HttpRequest object(#%d) from the HttpRequestPool: %s", Z_OBJ_HANDLE_P(request), curl_multi_strerror(code)); - } else { - req->pool = NULL; - zend_llist_del_element(&pool->finished, request, http_request_pool_compare_handles); - zend_llist_del_element(&pool->handles, request, http_request_pool_compare_handles); - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "> %d HttpRequests remaining in pool %p\n", zend_llist_count(&pool->handles), pool); -#endif - - return SUCCESS; - } - return FAILURE; -} -/* }}} */ - -/* {{{ void http_request_pool_apply(http_request_pool *, http_request_pool_apply_func) */ -PHP_HTTP_API void _http_request_pool_apply(http_request_pool *pool, http_request_pool_apply_func cb) -{ - int count = zend_llist_count(&pool->handles); - - if (count) { - int i = 0; - zend_llist_position pos; - zval **handle, **handles = emalloc(count * sizeof(zval *)); - - for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) { - handles[i++] = *handle; - } - - /* should never happen */ - if (i != count) { - zend_error(E_ERROR, "number of fetched request handles do not match overall count"); - count = i; - } - - for (i = 0; i < count; ++i) { - if (cb(pool, handles[i])) { - break; - } - } - efree(handles); - } -} -/* }}} */ - -/* {{{ void http_request_pool_apply_with_arg(http_request_pool *, http_request_pool_apply_with_arg_func, void *) */ -PHP_HTTP_API void _http_request_pool_apply_with_arg(http_request_pool *pool, http_request_pool_apply_with_arg_func cb, void *arg) -{ - int count = zend_llist_count(&pool->handles); - - if (count) { - int i = 0; - zend_llist_position pos; - zval **handle, **handles = emalloc(count * sizeof(zval *)); - - for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) { - handles[i++] = *handle; - } - - /* should never happen */ - if (i != count) { - zend_error(E_ERROR, "number of fetched request handles do not match overall count"); - count = i; - } - - for (i = 0; i < count; ++i) { - if (cb(pool, handles[i], arg)) { - break; - } - } - efree(handles); - } -} -/* }}} */ - -/* {{{ void http_request_pool_detach_all(http_request_pool *) */ -PHP_HTTP_API void _http_request_pool_detach_all(http_request_pool *pool) -{ -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Detaching %d requests from pool %p\n", zend_llist_count(&pool->handles), pool); -#endif - http_request_pool_apply(pool, _http_request_pool_detach); -} -/* }}} */ - -/* {{{ STATUS http_request_pool_send(http_request_pool *) */ -PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool) -{ - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Attempt to send %d requests of pool %p\n", zend_llist_count(&pool->handles), pool); -#endif - -#ifdef HTTP_HAVE_EVENT - if (pool->useevents) { - do { -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "& Starting event dispatcher of pool %p\n", pool); -#endif - event_base_dispatch(HTTP_G->request.pool.event.base); - } while (pool->unfinished); - } else -#endif - { - while (http_request_pool_perform(pool)) { - if (SUCCESS != http_request_pool_select(pool)) { -#ifdef PHP_WIN32 - /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */ - http_error_ex(HE_WARNING, HTTP_E_SOCKET, "WinSock error: %d", WSAGetLastError()); -#else - http_error(HE_WARNING, HTTP_E_SOCKET, strerror(errno)); -#endif - return FAILURE; - } - } - } - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Finished sending %d HttpRequests of pool %p (still unfinished: %d)\n", zend_llist_count(&pool->handles), pool, pool->unfinished); -#endif - - return SUCCESS; -} -/* }}} */ - -/* {{{ void http_request_pool_dtor(http_request_pool *) */ -PHP_HTTP_API void _http_request_pool_dtor(http_request_pool *pool) -{ - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Destructing request pool %p\n", pool); -#endif - -#ifdef HTTP_HAVE_EVENT - efree(pool->timeout); -#endif - - http_request_pool_detach_all(pool); - - pool->unfinished = 0; - zend_llist_clean(&pool->finished); - zend_llist_clean(&pool->handles); - http_persistent_handle_release("http_request_pool", &pool->ch); -} -/* }}} */ - -#ifdef PHP_WIN32 -# define SELECT_ERROR SOCKET_ERROR -#else -# define SELECT_ERROR -1 -#endif - -/* {{{ STATUS http_request_pool_select(http_request_pool *) */ -PHP_HTTP_API STATUS _http_request_pool_select(http_request_pool *pool) -{ - return http_request_pool_select_ex(pool, NULL); -} -/* }}} */ - -/* {{{ STATUS http_request_pool_select_ex(http_request_pool *, struct timeval *) */ -PHP_HTTP_API STATUS _http_request_pool_select_ex(http_request_pool *pool, struct timeval *custom_timeout) -{ - int MAX; - fd_set R, W, E; - struct timeval timeout; - -#ifdef HTTP_HAVE_EVENT - if (pool->useevents) { - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); - http_error(HE_WARNING, HTTP_E_RUNTIME, "not implemented; use HttpRequest callbacks"); - return FAILURE; - } -#endif - - if (custom_timeout && timerisset(custom_timeout)) { - timeout = *custom_timeout; - } else { - http_request_pool_timeout(pool, &timeout); - } - - FD_ZERO(&R); - FD_ZERO(&W); - FD_ZERO(&E); - - if (CURLM_OK == curl_multi_fdset(pool->ch, &R, &W, &E, &MAX)) { - if (MAX == -1) { - http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / HTTP_MCROSEC)); - return SUCCESS; - } else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) { - return SUCCESS; - } - } - return FAILURE; -} -/* }}} */ - -/* {{{ int http_request_pool_perform(http_request_pool *) */ -PHP_HTTP_API int _http_request_pool_perform(http_request_pool *pool) -{ - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); - -#ifdef HTTP_HAVE_EVENT - if (pool->useevents) { - http_error(HE_WARNING, HTTP_E_RUNTIME, "not implemented; use HttpRequest callbacks"); - return FAILURE; - } -#endif - - while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(pool->ch, &pool->unfinished)); - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "%u unfinished requests of pool %p remaining\n", pool->unfinished, pool); -#endif - - http_request_pool_responsehandler(pool); - - return pool->unfinished; -} -/* }}} */ - -/* {{{ void http_request_pool_responsehandler(http_request_pool *) */ -void _http_request_pool_responsehandler(http_request_pool *pool) -{ - CURLMsg *msg; - int remaining = 0; - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); - - do { - msg = curl_multi_info_read(pool->ch, &remaining); - if (msg && CURLMSG_DONE == msg->msg) { - if (CURLE_OK != msg->data.result) { - http_request_storage *st = http_request_storage_get(msg->easy_handle); - http_error_ex(HE_WARNING, HTTP_E_REQUEST, "%s; %s (%s)", curl_easy_strerror(msg->data.result), st?st->errorbuffer:"", st?st->url:""); - } - http_request_pool_apply_with_arg(pool, _http_request_pool_apply_responsehandler, msg->easy_handle); - } - } while (remaining); -} -/* }}} */ - -/* {{{ int http_request_pool_apply_responsehandler(http_request_pool *, zval *, void *) */ -int _http_request_pool_apply_responsehandler(http_request_pool *pool, zval *req, void *ch) -{ -#ifdef ZTS - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); -#endif - getObjectEx(http_request_object, obj, req); - - if ((!ch) || obj->request->ch == (CURL *) ch) { - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Fetching data from HttpRequest(#%d) %p of pool %p\n", Z_OBJ_HANDLE_P(req), obj, obj->pool); -#endif - - ZVAL_ADDREF(req); - zend_llist_add_element(&obj->pool->finished, &req); - http_request_object_responsehandler(obj, req); - return 1; - } - return 0; -} -/* }}} */ - -/* {{{ struct timeval *_http_request_pool_timeout(http_request_pool *, struct timeval *) */ -struct timeval *_http_request_pool_timeout(http_request_pool *pool, struct timeval *timeout) -{ -#ifdef HAVE_CURL_MULTI_TIMEOUT - long max_tout = 1000; - - if ((CURLM_OK == curl_multi_timeout(pool->ch, &max_tout)) && (max_tout > 0)) { - timeout->tv_sec = max_tout / 1000; - timeout->tv_usec = (max_tout % 1000) * 1000; - } else { -#endif - timeout->tv_sec = 0; - timeout->tv_usec = 1000; -#ifdef HAVE_CURL_MULTI_TIMEOUT - } -#endif - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Calculating timeout (%lu, %lu) of pool %p\n", (ulong) timeout->tv_sec, (ulong) timeout->tv_usec, pool); -#endif - - return timeout; -} -/* }}} */ - -/*#*/ - -/* {{{ static int http_request_pool_compare_handles(void *, void *) */ -static int http_request_pool_compare_handles(void *h1, void *h2) -{ - return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2)); -} -/* }}} */ - -#ifdef HTTP_HAVE_EVENT -/* {{{ static void http_request_pool_timeout_callback(int, short, void *) */ -static void http_request_pool_timeout_callback(int socket, short action, void *event_data) -{ - http_request_pool *pool = event_data; - - if (pool->useevents) { - CURLMcode rc; - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Timeout occurred of pool %p\n", pool); -#endif - - while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket(pool->ch, CURL_SOCKET_TIMEOUT, &pool->unfinished))); - - if (CURLM_OK != rc) { - http_error(HE_WARNING, HTTP_E_SOCKET, curl_multi_strerror(rc)); - } - - http_request_pool_responsehandler(pool); - } -} -/* }}} */ - -/* {{{ static void http_request_pool_event_callback(int, short, void *) */ -static void http_request_pool_event_callback(int socket, short action, void *event_data) -{ - http_request_pool_event *ev = event_data; - http_request_pool *pool = ev->pool; - - if (pool->useevents) { - CURLMcode rc = CURLE_OK; - TSRMLS_FETCH_FROM_CTX(ev->pool->tsrm_ls); - -#if HTTP_DEBUG_REQPOOLS - { - static const char event_strings[][20] = {"NONE","TIMEOUT","READ","TIMEOUT|READ","WRITE","TIMEOUT|WRITE","READ|WRITE","TIMEOUT|READ|WRITE","SIGNAL"}; - fprintf(stderr, "Event on socket %d (%s) event %p of pool %p\n", socket, event_strings[action], ev, pool); - } -#endif - - /* don't use 'ev' below this loop as it might 've been freed in the socket callback */ - do { -#ifdef HAVE_CURL_MULTI_SOCKET_ACTION - switch (action & (EV_READ|EV_WRITE)) { - case EV_READ: - rc = curl_multi_socket_action(pool->ch, socket, CURL_CSELECT_IN, &pool->unfinished); - break; - case EV_WRITE: - rc = curl_multi_socket_action(pool->ch, socket, CURL_CSELECT_OUT, &pool->unfinished); - break; - case EV_READ|EV_WRITE: - rc = curl_multi_socket_action(pool->ch, socket, CURL_CSELECT_IN|CURL_CSELECT_OUT, &pool->unfinished); - break; - default: - http_error_ex(HE_WARNING, HTTP_E_SOCKET, "Unknown event %d", (int) action); - return; - } -#else - rc = curl_multi_socket(pool->ch, socket, &pool->unfinished); -#endif - } while (CURLM_CALL_MULTI_PERFORM == rc); - - switch (rc) { - case CURLM_BAD_SOCKET: -#if 0 - fprintf(stderr, "!!! Bad socket: %d (%d)\n", socket, (int) action); -#endif - case CURLM_OK: - break; - default: - http_error(HE_WARNING, HTTP_E_SOCKET, curl_multi_strerror(rc)); - break; - } - - http_request_pool_responsehandler(pool); - - /* remove timeout if there are no transfers left */ - if (!pool->unfinished && event_initialized(pool->timeout) && event_pending(pool->timeout, EV_TIMEOUT, NULL)) { - event_del(pool->timeout); -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Removed timeout of pool %p\n", pool); -#endif - } - } -} -/* }}} */ - -/* {{{ static int http_request_pool_socket_callback(CURL *, curl_socket_t, int, void *, void *) */ -static int http_request_pool_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data) -{ - http_request_pool *pool = socket_data; - - if (pool->useevents) { - int events = EV_PERSIST; - http_request_pool_event *ev = assign_data; - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); - - if (!ev) { - ev = ecalloc(1, sizeof(http_request_pool_event)); - ev->pool = pool; - curl_multi_assign(pool->ch, sock, ev); - event_base_set(HTTP_G->request.pool.event.base, &ev->evnt); - } else { - event_del(&ev->evnt); - } - -#if HTTP_DEBUG_REQPOOLS - { - static const char action_strings[][8] = {"NONE", "IN", "OUT", "INOUT", "REMOVE"}; - http_request *r; - curl_easy_getinfo(easy, CURLINFO_PRIVATE, &r); - fprintf(stderr, "Callback on socket %2d (%8s) event %p of pool %p (%d)\n", (int) sock, action_strings[action], ev, pool, pool->unfinished); - } -#endif - - switch (action) { - case CURL_POLL_IN: - events |= EV_READ; - break; - case CURL_POLL_OUT: - events |= EV_WRITE; - break; - case CURL_POLL_INOUT: - events |= EV_READ|EV_WRITE; - break; - - case CURL_POLL_REMOVE: - efree(ev); - case CURL_POLL_NONE: - return 0; - - default: - http_error_ex(HE_WARNING, HTTP_E_SOCKET, "Unknown socket action %d", action); - return -1; - } - - event_set(&ev->evnt, sock, events, http_request_pool_event_callback, ev); - event_add(&ev->evnt, NULL); - } - - return 0; -} -/* }}} */ - -/* {{{ static void http_request_pool_timer_callback(CURLM *, long, void*) */ -static void http_request_pool_timer_callback(CURLM *multi, long timeout_ms, void *timer_data) -{ - http_request_pool *pool = timer_data; - - if (pool->useevents) { - TSRMLS_FETCH_FROM_CTX(pool->tsrm_ls); - struct timeval timeout; - - if (!event_initialized(pool->timeout)) { - event_set(pool->timeout, -1, 0, http_request_pool_timeout_callback, pool); - event_base_set(HTTP_G->request.pool.event.base, pool->timeout); - } else if (event_pending(pool->timeout, EV_TIMEOUT, NULL)) { - event_del(pool->timeout); - } - - if (timeout_ms > 0) { - timeout.tv_sec = timeout_ms / 1000; - timeout.tv_usec = (timeout_ms % 1000) * 1000; - } else { - http_request_pool_timeout(pool, &timeout); - } - - event_add(pool->timeout, &timeout); - -#if HTTP_DEBUG_REQPOOLS - fprintf(stderr, "Updating timeout %lu (%lu, %lu) of pool %p\n", (ulong) timeout_ms, (ulong) timeout.tv_sec, (ulong) timeout.tv_usec, pool); -#endif - } -} -/* }}} */ -#endif /* HTTP_HAVE_EVENT */ - -#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */ - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_requestdatashare_object.c b/http_requestdatashare_object.c deleted file mode 100644 index eed7d6b..0000000 --- a/http_requestdatashare_object.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_CURL -#include "php_http.h" - -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) - -#include "zend_interfaces.h" - -#include "php_http_api.h" -#include "php_http_exception_object.h" -#include "php_http_request_api.h" -#include "php_http_request_object.h" -#include "php_http_request_datashare_api.h" -#include "php_http_requestdatashare_object.h" - -#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpRequestDataShare, method, 0, req_args) -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpRequestDataShare, method, 0) -#define HTTP_RSHARE_ME(method, visibility) PHP_ME(HttpRequestDataShare, method, HTTP_ARGS(HttpRequestDataShare, method), visibility) - -#if defined(HAVE_SPL) && !defined(WONKY) -/* SPL doesn't install its headers */ -extern PHPAPI zend_class_entry *spl_ce_Countable; -#endif - -HTTP_EMPTY_ARGS(__destruct); -HTTP_EMPTY_ARGS(count); - -HTTP_BEGIN_ARGS(attach, 1) - HTTP_ARG_OBJ(HttpRequest, request, 0) -HTTP_END_ARGS; -HTTP_BEGIN_ARGS(detach, 1) - HTTP_ARG_OBJ(HttpRequest, request, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(reset); - -HTTP_BEGIN_ARGS(factory, 0) - HTTP_ARG_VAL(global, 0) - HTTP_ARG_VAL(class_name, 0) -HTTP_END_ARGS; - -#ifndef WONKY -HTTP_BEGIN_ARGS(singleton, 0) - HTTP_ARG_VAL(global, 0) -HTTP_END_ARGS; -#endif - - -#define http_requestdatashare_object_read_prop _http_requestdatashare_object_read_prop -static zval *_http_requestdatashare_object_read_prop(zval *object, zval *member, int type ZEND_LITERAL_KEY_DC TSRMLS_DC); -#define http_requestdatashare_object_write_prop _http_requestdatashare_object_write_prop -static void _http_requestdatashare_object_write_prop(zval *object, zval *member, zval *value ZEND_LITERAL_KEY_DC TSRMLS_DC); -#define http_requestdatashare_instantiate(t, g) _http_requestdatashare_instantiate((t), (g) TSRMLS_CC) -static inline zval *_http_requestdatashare_instantiate(zval *this_ptr, zend_bool global TSRMLS_DC); - -#define THIS_CE http_requestdatashare_object_ce -zend_class_entry *http_requestdatashare_object_ce; -zend_function_entry http_requestdatashare_object_fe[] = { - HTTP_RSHARE_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR) - HTTP_RSHARE_ME(count, ZEND_ACC_PUBLIC) - HTTP_RSHARE_ME(attach, ZEND_ACC_PUBLIC) - HTTP_RSHARE_ME(detach, ZEND_ACC_PUBLIC) - HTTP_RSHARE_ME(reset, ZEND_ACC_PUBLIC) - HTTP_RSHARE_ME(factory, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) -#ifndef WONKY - HTTP_RSHARE_ME(singleton, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) -#endif - EMPTY_FUNCTION_ENTRY -}; -static zend_object_handlers http_requestdatashare_object_handlers; - -PHP_MINIT_FUNCTION(http_requestdatashare_object) -{ - HTTP_REGISTER_CLASS_EX(HttpRequestDataShare, http_requestdatashare_object, NULL, 0); - http_requestdatashare_object_handlers.clone_obj = NULL; - http_requestdatashare_object_handlers.read_property = http_requestdatashare_object_read_prop; - http_requestdatashare_object_handlers.write_property = http_requestdatashare_object_write_prop; - -#if defined(HAVE_SPL) && !defined(WONKY) - zend_class_implements(http_requestdatashare_object_ce TSRMLS_CC, 1, spl_ce_Countable); -#endif - - zend_declare_property_null(THIS_CE, ZEND_STRS("instance")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); - zend_declare_property_bool(THIS_CE, ZEND_STRS("cookie")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); - zend_declare_property_bool(THIS_CE, ZEND_STRS("dns")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); - zend_declare_property_bool(THIS_CE, ZEND_STRS("ssl")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); - zend_declare_property_bool(THIS_CE, ZEND_STRS("connect")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); - - return SUCCESS; -} - -zend_object_value _http_requestdatashare_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return http_requestdatashare_object_new_ex(ce, NULL, NULL); -} - -zend_object_value _http_requestdatashare_object_new_ex(zend_class_entry *ce, http_request_datashare *share, http_requestdatashare_object **ptr TSRMLS_DC) -{ - zend_object_value ov; - http_requestdatashare_object *o; - - o = ecalloc(1, sizeof(http_requestdatashare_object)); - o->zo.ce = ce; - - if (share) { - o->share = share; - } else { - o->share = http_request_datashare_new(); - } - - if (ptr) { - *ptr = o; - } - -#ifdef ZEND_ENGINE_2_4 - zend_object_std_init(o, ce TSRMLS_CC); - object_properties_init(o, ce); -#else - ALLOC_HASHTABLE(OBJ_PROP(o)); - zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); -#endif - - ov.handle = putObject(http_requestdatashare_object, o); - ov.handlers = &http_requestdatashare_object_handlers; - - return ov; -} - -void _http_requestdatashare_object_free(zend_object *object TSRMLS_DC) -{ - http_requestdatashare_object *o = (http_requestdatashare_object *) object; - - if (!o->share->persistent) { - http_request_datashare_free(&o->share); - } - freeObject(o); -} - -static zval *_http_requestdatashare_object_read_prop(zval *object, zval *member, int type ZEND_LITERAL_KEY_DC TSRMLS_DC) -{ - if (type == BP_VAR_W && -#ifdef ZEND_ENGINE_2_4 - zend_hash_exists(&THIS_CE->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) -#else - zend_hash_exists(&THIS_CE->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) -#endif - ) { - zend_error(E_ERROR, "Cannot access HttpRequestDataShare default properties by reference or array key/index"); - return NULL; - } - - return zend_get_std_object_handlers()->read_property(object, member, type ZEND_LITERAL_KEY_CC TSRMLS_CC); -} - -static void _http_requestdatashare_object_write_prop(zval *object, zval *member, zval *value ZEND_LITERAL_KEY_DC TSRMLS_DC) -{ - if ( -#ifdef ZEND_ENGINE_2_4 - zend_hash_exists(&THIS_CE->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) -#else - zend_hash_exists(&THIS_CE->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) -#endif - ) { - int status; - getObjectEx(http_requestdatashare_object, obj, object); - - status = http_request_datashare_set(obj->share, Z_STRVAL_P(member), Z_STRLEN_P(member), (zend_bool) i_zend_is_true(value)); - if (SUCCESS != status) { - return; - } - } - - zend_get_std_object_handlers()->write_property(object, member, value ZEND_LITERAL_KEY_CC TSRMLS_CC); -} - -/* {{{ proto void HttpRequestDataShare::__destruct() - Clean up HttpRequestDataShare object. */ -PHP_METHOD(HttpRequestDataShare, __destruct) -{ - NO_ARGS { - getObject(http_requestdatashare_object, obj); - http_request_datashare_detach_all(obj->share); - } -} -/* }}} */ - -/* {{{ proto int HttpRequestDataShare::count() - Implements Countable::count(). */ -PHP_METHOD(HttpRequestDataShare, count) -{ - getObject(http_requestdatashare_object, obj); - - NO_ARGS; - - RETURN_LONG(zend_llist_count(HTTP_RSHARE_HANDLES(obj->share))); -} -/* }}} */ - -PHP_METHOD(HttpRequestDataShare, attach) -{ - zval *request; - getObject(http_requestdatashare_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) { - RETURN_FALSE; - } - - RETURN_SUCCESS(http_request_datashare_attach(obj->share, request)); -} - -PHP_METHOD(HttpRequestDataShare, detach) -{ - zval *request; - getObject(http_requestdatashare_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) { - RETURN_FALSE; - } - - RETURN_SUCCESS(http_request_datashare_detach(obj->share, request)); -} - -PHP_METHOD(HttpRequestDataShare, reset) -{ - NO_ARGS { - getObject(http_requestdatashare_object, obj); - http_request_datashare_detach_all(obj->share); - } -} - -PHP_METHOD(HttpRequestDataShare, factory) -{ - zend_bool global = 0; - char *cn = NULL; - int cl = 0; - zend_object_value ov; - - SET_EH_THROW_HTTP(); - if ( SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bs", &global, &cn, &cl) && - SUCCESS == http_object_new(&ov, cn, cl, _http_requestdatashare_object_new_ex, http_requestdatashare_object_ce, NULL, NULL)) { - RETVAL_OBJVAL(ov, 0); - http_requestdatashare_instantiate(return_value, global); - } - SET_EH_NORMAL(); -} - -#ifndef WONKY -/* {{{ proto static HttpRequestDataShare HttpRequestDataShare::singleton([bool global = false]) - Get a single instance (differentiates between the global setting). */ -PHP_METHOD(HttpRequestDataShare, singleton) -{ - zend_bool global = 0; - zval *instance = *zend_std_get_static_property(THIS_CE, ZEND_STRS("instance")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC); - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &global)) { - zval **zobj_ptr = NULL, *zobj = NULL; - - if (Z_TYPE_P(instance) == IS_ARRAY) { - if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(instance), global, (void *) &zobj_ptr)) { - RETVAL_ZVAL(*zobj_ptr, 1, 0); - } else { - zobj = http_requestdatashare_instantiate(NULL, global); - add_index_zval(instance, global, zobj); - RETVAL_OBJECT(zobj, 1); - } - } else { - MAKE_STD_ZVAL(instance); - array_init(instance); - - zobj = http_requestdatashare_instantiate(NULL, global); - add_index_zval(instance, global, zobj); - RETVAL_OBJECT(zobj, 1); - - zend_update_static_property(THIS_CE, ZEND_STRS("instance")-1, instance TSRMLS_CC); - zval_ptr_dtor(&instance); - } - } - SET_EH_NORMAL(); -} -/* }}} */ -#endif /* !WONKY */ - -static inline zval *_http_requestdatashare_instantiate(zval *this_ptr, zend_bool global TSRMLS_DC) -{ - if (!this_ptr) { - MAKE_STD_ZVAL(this_ptr); - Z_TYPE_P(this_ptr) = IS_OBJECT; - this_ptr->value.obj = http_requestdatashare_object_new_ex(http_requestdatashare_object_ce, global ? http_request_datashare_global_get() : NULL, NULL); - } - if (global) { - if (HTTP_G->request.datashare.cookie) { - zend_update_property_bool(THIS_CE, getThis(), ZEND_STRS("cookie")-1, HTTP_G->request.datashare.cookie TSRMLS_CC); - } - if (HTTP_G->request.datashare.dns) { - zend_update_property_bool(THIS_CE, getThis(), ZEND_STRS("dns")-1, HTTP_G->request.datashare.dns TSRMLS_CC); - } - if (HTTP_G->request.datashare.ssl) { - zend_update_property_bool(THIS_CE, getThis(), ZEND_STRS("ssl")-1, HTTP_G->request.datashare.ssl TSRMLS_CC); - } - if (HTTP_G->request.datashare.connect) { - zend_update_property_bool(THIS_CE, getThis(), ZEND_STRS("connect")-1, HTTP_G->request.datashare.connect TSRMLS_CC); - } - } - return this_ptr; -} - -#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_requestpool_object.c b/http_requestpool_object.c deleted file mode 100644 index a0f219c..0000000 --- a/http_requestpool_object.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_CURL -#include "php_http.h" - -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) - -#include "zend_interfaces.h" - -#include "php_http_api.h" -#include "php_http_exception_object.h" -#include "php_http_request_api.h" -#include "php_http_request_object.h" -#include "php_http_request_pool_api.h" -#include "php_http_requestpool_object.h" - -#if defined(HAVE_SPL) && !defined(WONKY) -/* SPL doesn't install its headers */ -extern PHPAPI zend_class_entry *spl_ce_Countable; -#endif - -#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpRequestPool, method, 0, req_args) -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpRequestPool, method, 0) -#define HTTP_REQPOOL_ME(method, visibility) PHP_ME(HttpRequestPool, method, HTTP_ARGS(HttpRequestPool, method), visibility) - -HTTP_EMPTY_ARGS(__construct); - -HTTP_EMPTY_ARGS(__destruct); -HTTP_EMPTY_ARGS(reset); - -HTTP_BEGIN_ARGS(attach, 1) - HTTP_ARG_OBJ(HttpRequest, request, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(detach, 1) - HTTP_ARG_OBJ(HttpRequest, request, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(send); -HTTP_EMPTY_ARGS(socketPerform); -HTTP_BEGIN_ARGS(socketSelect, 0) - HTTP_ARG_VAL(timeout, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(valid); -HTTP_EMPTY_ARGS(current); -HTTP_EMPTY_ARGS(key); -HTTP_EMPTY_ARGS(next); -HTTP_EMPTY_ARGS(rewind); - -HTTP_EMPTY_ARGS(count); - -HTTP_EMPTY_ARGS(getAttachedRequests); -HTTP_EMPTY_ARGS(getFinishedRequests); - -HTTP_BEGIN_ARGS(enablePipelining, 0) - HTTP_ARG_VAL(enable, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(enableEvents, 0) - HTTP_ARG_VAL(enable, 0) -HTTP_END_ARGS; - -zend_class_entry *http_requestpool_object_ce; -zend_function_entry http_requestpool_object_fe[] = { - HTTP_REQPOOL_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - HTTP_REQPOOL_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR) - HTTP_REQPOOL_ME(attach, ZEND_ACC_PUBLIC) - HTTP_REQPOOL_ME(detach, ZEND_ACC_PUBLIC) - HTTP_REQPOOL_ME(send, ZEND_ACC_PUBLIC) - HTTP_REQPOOL_ME(reset, ZEND_ACC_PUBLIC) - - HTTP_REQPOOL_ME(socketPerform, ZEND_ACC_PROTECTED) - HTTP_REQPOOL_ME(socketSelect, ZEND_ACC_PROTECTED) - - /* implements Iterator */ - HTTP_REQPOOL_ME(valid, ZEND_ACC_PUBLIC) - HTTP_REQPOOL_ME(current, ZEND_ACC_PUBLIC) - HTTP_REQPOOL_ME(key, ZEND_ACC_PUBLIC) - HTTP_REQPOOL_ME(next, ZEND_ACC_PUBLIC) - HTTP_REQPOOL_ME(rewind, ZEND_ACC_PUBLIC) - - /* implmenents Countable */ - HTTP_REQPOOL_ME(count, ZEND_ACC_PUBLIC) - - HTTP_REQPOOL_ME(getAttachedRequests, ZEND_ACC_PUBLIC) - HTTP_REQPOOL_ME(getFinishedRequests, ZEND_ACC_PUBLIC) - - HTTP_REQPOOL_ME(enablePipelining, ZEND_ACC_PUBLIC) - HTTP_REQPOOL_ME(enableEvents, ZEND_ACC_PUBLIC) - - EMPTY_FUNCTION_ENTRY -}; -static zend_object_handlers http_requestpool_object_handlers; - -PHP_MINIT_FUNCTION(http_requestpool_object) -{ - HTTP_REGISTER_CLASS_EX(HttpRequestPool, http_requestpool_object, NULL, 0); - http_requestpool_object_handlers.clone_obj = NULL; - -#if defined(HAVE_SPL) && !defined(WONKY) - zend_class_implements(http_requestpool_object_ce TSRMLS_CC, 2, spl_ce_Countable, zend_ce_iterator); -#else - zend_class_implements(http_requestpool_object_ce TSRMLS_CC, 1, zend_ce_iterator); -#endif - - return SUCCESS; -} - -zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC) -{ - zend_object_value ov; - http_requestpool_object *o; - - o = ecalloc(1, sizeof(http_requestpool_object)); - o->zo.ce = ce; - - http_request_pool_init(&o->pool); - -#ifdef ZEND_ENGINE_2_4 - zend_object_std_init(o, ce TSRMLS_CC); - object_properties_init(o, ce); -#else - ALLOC_HASHTABLE(OBJ_PROP(o)); - zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); -#endif - - ov.handle = putObject(http_requestpool_object, o); - ov.handlers = &http_requestpool_object_handlers; - - return ov; -} - -void _http_requestpool_object_free(zend_object *object TSRMLS_DC) -{ - http_requestpool_object *o = (http_requestpool_object *) object; - - http_request_pool_dtor(&o->pool); - freeObject(o); -} - -#define http_requestpool_object_llist2array _http_requestpool_object_llist2array -static void _http_requestpool_object_llist2array(zval **req, zval *array TSRMLS_DC) -{ - ZVAL_ADDREF(*req); - add_next_index_zval(array, *req); -} - -/* ### USERLAND ### */ - -/* {{{ proto void HttpRequestPool::__construct([HttpRequest request[, ...]]) - Creates a new HttpRequestPool object instance. */ -PHP_METHOD(HttpRequestPool, __construct) -{ - int argc = ZEND_NUM_ARGS(); - zval ***argv = safe_emalloc(argc, sizeof(zval *), 0); - getObject(http_requestpool_object, obj); - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_get_parameters_array_ex(argc, argv)) { - int i; - - for (i = 0; i < argc; ++i) { - if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), http_request_object_ce TSRMLS_CC)) { - http_request_pool_attach(&obj->pool, *(argv[i])); - } - } - } - efree(argv); - http_final(HTTP_EX_CE(request_pool)); - SET_EH_NORMAL(); -} -/* }}} */ - -/* {{{ proto void HttpRequestPool::__destruct() - Clean up HttpRequestPool object. */ -PHP_METHOD(HttpRequestPool, __destruct) -{ - getObject(http_requestpool_object, obj); - - NO_ARGS; - - http_request_pool_detach_all(&obj->pool); -} -/* }}} */ - -/* {{{ proto void HttpRequestPool::reset() - Detach all attached HttpRequest objects. */ -PHP_METHOD(HttpRequestPool, reset) -{ - getObject(http_requestpool_object, obj); - - NO_ARGS; - - obj->iterator.pos = 0; - http_request_pool_detach_all(&obj->pool); -} - -/* {{{ proto bool HttpRequestPool::attach(HttpRequest request) - Attach an HttpRequest object to this HttpRequestPool. WARNING: set all options prior attaching! */ -PHP_METHOD(HttpRequestPool, attach) -{ - zval *request; - STATUS status = FAILURE; - getObject(http_requestpool_object, obj); - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) { - if (obj->iterator.pos > 0 && obj->iterator.pos < zend_llist_count(&obj->pool.handles)) { - http_error(HE_THROW, HTTP_E_REQUEST_POOL, "Cannot attach to the HttpRequestPool while the iterator is active"); - } else { - status = http_request_pool_attach(&obj->pool, request); - } - } - SET_EH_NORMAL(); - RETURN_SUCCESS(status); -} -/* }}} */ - -/* {{{ proto bool HttpRequestPool::detach(HttpRequest request) - Detach an HttpRequest object from this HttpRequestPool. */ -PHP_METHOD(HttpRequestPool, detach) -{ - zval *request; - STATUS status = FAILURE; - getObject(http_requestpool_object, obj); - - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) { - obj->iterator.pos = -1; - status = http_request_pool_detach(&obj->pool, request); - } - SET_EH_NORMAL(); - RETURN_SUCCESS(status); -} -/* }}} */ - -/* {{{ proto bool HttpRequestPool::send() - Send all attached HttpRequest objects in parallel. */ -PHP_METHOD(HttpRequestPool, send) -{ - STATUS status; - getObject(http_requestpool_object, obj); - - NO_ARGS; - - SET_EH_THROW_HTTP(); - status = http_request_pool_send(&obj->pool); - SET_EH_NORMAL(); - - /* rethrow as HttpRequestPoolException */ - http_final(HTTP_EX_CE(request_pool)); - - RETURN_SUCCESS(status); -} -/* }}} */ - -/* {{{ proto protected bool HttpRequestPool::socketPerform() - Returns TRUE until each request has finished its transaction. */ -PHP_METHOD(HttpRequestPool, socketPerform) -{ - getObject(http_requestpool_object, obj); - - NO_ARGS; - - if (0 < http_request_pool_perform(&obj->pool)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } -} -/* }}} */ - -/* {{{ proto protected bool HttpRequestPool::socketSelect([double timeout]) */ -PHP_METHOD(HttpRequestPool, socketSelect) -{ - double timeout = 0; - struct timeval custom_timeout, *custom_timeout_ptr = NULL; - getObject(http_requestpool_object, obj); - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) { - RETURN_FALSE; - } - if (ZEND_NUM_ARGS() && timeout > 0) { - custom_timeout.tv_sec = (time_t) timeout; - custom_timeout.tv_usec = HTTP_USEC(timeout) % HTTP_MCROSEC; - custom_timeout_ptr = &custom_timeout; - } - - RETURN_SUCCESS(http_request_pool_select_ex(&obj->pool, custom_timeout_ptr)); -} -/* }}} */ - -/* {{{ proto bool HttpRequestPool::valid() - Implements Iterator::valid(). */ -PHP_METHOD(HttpRequestPool, valid) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_requestpool_object, obj); - RETURN_BOOL(obj->iterator.pos >= 0 && obj->iterator.pos < zend_llist_count(&obj->pool.handles)); - } -} -/* }}} */ - -/* {{{ proto HttpRequest HttpRequestPool::current() - Implements Iterator::current(). */ -PHP_METHOD(HttpRequestPool, current) -{ - NO_ARGS; - - if (return_value_used) { - long pos = 0; - zval **current = NULL; - zend_llist_position lpos; - getObject(http_requestpool_object, obj); - - if (obj->iterator.pos < zend_llist_count(&obj->pool.handles)) { - for ( current = zend_llist_get_first_ex(&obj->pool.handles, &lpos); - current && obj->iterator.pos != pos++; - current = zend_llist_get_next_ex(&obj->pool.handles, &lpos)); - if (current) { - RETURN_OBJECT(*current, 1); - } - } - RETURN_NULL(); - } -} -/* }}} */ - -/* {{{ proto int HttpRequestPool::key() - Implements Iterator::key(). */ -PHP_METHOD(HttpRequestPool, key) -{ - NO_ARGS; - - if (return_value_used) { - getObject(http_requestpool_object, obj); - RETURN_LONG(obj->iterator.pos); - } -} -/* }}} */ - -/* {{{ proto void HttpRequestPool::next() - Implements Iterator::next(). */ -PHP_METHOD(HttpRequestPool, next) -{ - NO_ARGS { - getObject(http_requestpool_object, obj); - ++(obj->iterator.pos); - } -} -/* }}} */ - -/* {{{ proto void HttpRequestPool::rewind() - Implements Iterator::rewind(). */ -PHP_METHOD(HttpRequestPool, rewind) -{ - NO_ARGS { - getObject(http_requestpool_object, obj); - obj->iterator.pos = 0; - } -} -/* }}} */ - -/* {{{ proto int HttpRequestPool::count() - Implements Countable::count(). */ -PHP_METHOD(HttpRequestPool, count) -{ - NO_ARGS { - getObject(http_requestpool_object, obj); - RETURN_LONG((long) zend_llist_count(&obj->pool.handles)); - } -} -/* }}} */ - -/* {{{ proto array HttpRequestPool::getAttachedRequests() - Get attached HttpRequest objects. */ -PHP_METHOD(HttpRequestPool, getAttachedRequests) -{ - getObject(http_requestpool_object, obj); - - NO_ARGS; - - array_init(return_value); - zend_llist_apply_with_argument(&obj->pool.handles, - (llist_apply_with_arg_func_t) http_requestpool_object_llist2array, - return_value TSRMLS_CC); -} -/* }}} */ - -/* {{{ proto array HttpRequestPool::getFinishedRequests() - Get attached HttpRequest objects that already have finished their work. */ -PHP_METHOD(HttpRequestPool, getFinishedRequests) -{ - getObject(http_requestpool_object, obj); - - NO_ARGS; - - array_init(return_value); - zend_llist_apply_with_argument(&obj->pool.finished, - (llist_apply_with_arg_func_t) http_requestpool_object_llist2array, - return_value TSRMLS_CC); -} -/* }}} */ - -/* {{{ proto bool HttpRequestPool::enablePipelining([bool enable = true]) - Enables pipelining support for all attached requests if support in libcurl is given. */ -PHP_METHOD(HttpRequestPool, enablePipelining) -{ - zend_bool enable = 1; -#if defined(HAVE_CURL_MULTI_SETOPT) && HTTP_CURL_VERSION(7,16,0) - getObject(http_requestpool_object, obj); -#endif - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) { - RETURN_FALSE; - } -#if defined(HAVE_CURL_MULTI_SETOPT) && HTTP_CURL_VERSION(7,16,0) - if (CURLM_OK == curl_multi_setopt(obj->pool.ch, CURLMOPT_PIPELINING, (long) enable)) { - RETURN_TRUE; - } -#endif - RETURN_FALSE; -} -/* }}} */ - -/* {{{ proto bool HttpRequestPool::enableEvents([bool enable = true]) - Enables event-driven I/O if support in libcurl is given. */ -PHP_METHOD(HttpRequestPool, enableEvents) -{ - zend_bool enable = 1; -#if defined(HTTP_HAVE_EVENT) - getObject(http_requestpool_object, obj); -#endif - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) { -#if defined(HTTP_HAVE_EVENT) - obj->pool.useevents = enable; - RETURN_TRUE; -#endif - } - RETURN_FALSE; -} -/* }}} */ - -#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_response_object.c b/http_response_object.c deleted file mode 100644 index c8d45cc..0000000 --- a/http_response_object.c +++ /dev/null @@ -1,927 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#define HTTP_WANT_MAGIC -#include "php_http.h" - -/* broken static properties in PHP 5.0 */ -#if defined(ZEND_ENGINE_2) && !defined(WONKY) - -#include "php_ini.h" - -#include "php_http_api.h" -#include "php_http_cache_api.h" -#include "php_http_exception_object.h" -#include "php_http_headers_api.h" -#include "php_http_response_object.h" -#include "php_http_send_api.h" - -#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpResponse, method, 0, req_args) -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpResponse, method, 0) -#define HTTP_RESPONSE_ME(method, visibility) PHP_ME(HttpResponse, method, HTTP_ARGS(HttpResponse, method), visibility|ZEND_ACC_STATIC) -#define HTTP_RESPONSE_ALIAS(method, func) HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpResponse, method)) - -HTTP_BEGIN_ARGS(setHeader, 1) - HTTP_ARG_VAL(name, 0) - HTTP_ARG_VAL(value, 0) - HTTP_ARG_VAL(replace, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(getHeader, 0) - HTTP_ARG_VAL(name, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getETag); -HTTP_BEGIN_ARGS(setETag, 1) - HTTP_ARG_VAL(etag, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getLastModified); -HTTP_BEGIN_ARGS(setLastModified, 1) - HTTP_ARG_VAL(timestamp, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getCache); -HTTP_BEGIN_ARGS(setCache, 1) - HTTP_ARG_VAL(cache, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getGzip); -HTTP_BEGIN_ARGS(setGzip, 1) - HTTP_ARG_VAL(gzip, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getCacheControl); -HTTP_BEGIN_ARGS(setCacheControl, 1) - HTTP_ARG_VAL(cache_control, 0) - HTTP_ARG_VAL(max_age, 0) - HTTP_ARG_VAL(must_revalidate, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getContentType); -HTTP_BEGIN_ARGS(setContentType, 1) - HTTP_ARG_VAL(content_type, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(guessContentType, 1) - HTTP_ARG_VAL(magic_file, 0) - HTTP_ARG_VAL(magic_mode, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getContentDisposition); -HTTP_BEGIN_ARGS(setContentDisposition, 1) - HTTP_ARG_VAL(filename, 0) - HTTP_ARG_VAL(send_inline, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getThrottleDelay); -HTTP_BEGIN_ARGS(setThrottleDelay, 1) - HTTP_ARG_VAL(seconds, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getBufferSize); -HTTP_BEGIN_ARGS(setBufferSize, 1) - HTTP_ARG_VAL(bytes, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getData); -HTTP_BEGIN_ARGS(setData, 1) - HTTP_ARG_VAL(data, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getStream); -HTTP_BEGIN_ARGS(setStream, 1) - HTTP_ARG_VAL(stream, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getFile); -HTTP_BEGIN_ARGS(setFile, 1) - HTTP_ARG_VAL(filepath, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(send, 0) - HTTP_ARG_VAL(clean_ob, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(capture); - -HTTP_BEGIN_ARGS(redirect, 0) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(params, 0) - HTTP_ARG_VAL(session, 0) - HTTP_ARG_VAL(permanent, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(status, 1) - HTTP_ARG_VAL(code, 0) -HTTP_END_ARGS; - -HTTP_EMPTY_ARGS(getRequestHeaders); -HTTP_EMPTY_ARGS(getRequestBody); -HTTP_EMPTY_ARGS(getRequestBodyStream); - -#define THIS_CE http_response_object_ce -zend_class_entry *http_response_object_ce; -zend_function_entry http_response_object_fe[] = { - - HTTP_RESPONSE_ME(setHeader, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getHeader, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setETag, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getETag, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setLastModified, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getLastModified, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setContentDisposition, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getContentDisposition, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setContentType, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getContentType, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(guessContentType, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setCache, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getCache, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setCacheControl, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getCacheControl, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setGzip, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getGzip, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setThrottleDelay, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getThrottleDelay, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setBufferSize, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getBufferSize, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setData, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getData, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setFile, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getFile, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(setStream, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(getStream, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ME(send, ZEND_ACC_PUBLIC) - HTTP_RESPONSE_ME(capture, ZEND_ACC_PUBLIC) - - HTTP_RESPONSE_ALIAS(redirect, http_redirect) - HTTP_RESPONSE_ALIAS(status, http_send_status) - HTTP_RESPONSE_ALIAS(getRequestHeaders, http_get_request_headers) - HTTP_RESPONSE_ALIAS(getRequestBody, http_get_request_body) - HTTP_RESPONSE_ALIAS(getRequestBodyStream, http_get_request_body_stream) - - EMPTY_FUNCTION_ENTRY -}; - -PHP_MINIT_FUNCTION(http_response_object) -{ - HTTP_REGISTER_CLASS(HttpResponse, http_response_object, NULL, 0); - - zend_declare_property_bool(THIS_CE, ZEND_STRS("sent")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); - zend_declare_property_bool(THIS_CE, ZEND_STRS("catch")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); - zend_declare_property_long(THIS_CE, ZEND_STRS("mode")-1, -1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); - zend_declare_property_long(THIS_CE, ZEND_STRS("stream")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("file")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("data")-1, (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); - zend_declare_property_bool(THIS_CE, ZEND_STRS("cache")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC); - zend_declare_property_bool(THIS_CE, ZEND_STRS("gzip")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("eTag")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC); - zend_declare_property_long(THIS_CE, ZEND_STRS("lastModified")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("cacheControl")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("contentType")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC); - zend_declare_property_null(THIS_CE, ZEND_STRS("contentDisposition")-1, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC); - zend_declare_property_long(THIS_CE, ZEND_STRS("bufferSize")-1, 0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC); - zend_declare_property_double(THIS_CE, ZEND_STRS("throttleDelay")-1, 0.0, (ZEND_ACC_STATIC|ZEND_ACC_PROTECTED) TSRMLS_CC); - -#ifndef WONKY - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT")-1, HTTP_REDIRECT TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_PERM")-1, HTTP_REDIRECT_PERM TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_FOUND")-1, HTTP_REDIRECT_FOUND TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_POST")-1, HTTP_REDIRECT_POST TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_PROXY")-1, HTTP_REDIRECT_PROXY TSRMLS_CC); - zend_declare_class_constant_long(THIS_CE, ZEND_STRS("REDIRECT_TEMP")-1, HTTP_REDIRECT_TEMP TSRMLS_CC); -#endif /* WONKY */ - - return SUCCESS; -} - -/* ### USERLAND ### */ - -/* {{{ proto static bool HttpResponse::setHeader(string name[, mixed value[, bool replace = true]]) - Send an HTTP header. */ -PHP_METHOD(HttpResponse, setHeader) -{ - zend_bool replace = 1; - char *name; - int name_len = 0; - zval *value = NULL; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/!b", &name, &name_len, &value, &replace)) { - RETURN_FALSE; - } - if (SG(headers_sent)) { - http_error(HE_WARNING, HTTP_E_HEADER, "Cannot add another header when headers have already been sent"); - RETURN_FALSE; - } - if (!name_len) { - http_error(HE_WARNING, HTTP_E_HEADER, "Cannot send anonymous headers"); - RETURN_FALSE; - } - http_send_header_zval_ex(name, name_len, &value, replace); - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto static mixed HttpResponse::getHeader([string name]) - Get header(s) about to be sent. */ -PHP_METHOD(HttpResponse, getHeader) -{ - char *name = NULL; - int name_len = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len)) { - RETURN_FALSE; - } - - if (name && name_len) { - zval **header; - HashTable headers_ht; - - zend_hash_init(&headers_ht, sizeof(zval *), NULL, ZVAL_PTR_DTOR, 0); - if ( (SUCCESS == http_get_response_headers(&headers_ht)) && - (SUCCESS == zend_hash_find(&headers_ht, name, name_len + 1, (void *) &header))) { - RETVAL_ZVAL(*header, 1, 0); - } else { - RETVAL_NULL(); - } - zend_hash_destroy(&headers_ht); - } else { - array_init(return_value); - http_get_response_headers(Z_ARRVAL_P(return_value)); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setCache(bool cache) - Whether it should be attempted to cache the entity. */ -PHP_METHOD(HttpResponse, setCache) -{ - zend_bool do_cache = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_cache)) { - RETURN_FALSE; - } - - RETURN_SUCCESS(zend_update_static_property_bool(THIS_CE, ZEND_STRS("cache")-1, do_cache TSRMLS_CC)); -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::getCache() - Get current caching setting. */ -PHP_METHOD(HttpResponse, getCache) -{ - NO_ARGS; - - if (return_value_used) { - zval *cache = http_zsep(IS_BOOL, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("cache")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(cache, 1, 1); - } -} -/* }}}*/ - -/* {{{ proto static bool HttpResponse::setGzip(bool gzip) - Enable on-thy-fly gzipping of the sent entity. */ -PHP_METHOD(HttpResponse, setGzip) -{ - zend_bool do_gzip = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_gzip)) { - RETURN_FALSE; - } - - RETURN_SUCCESS(zend_update_static_property_bool(THIS_CE, ZEND_STRS("gzip")-1, do_gzip TSRMLS_CC)); -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::getGzip() - Get current gzipping setting. */ -PHP_METHOD(HttpResponse, getGzip) -{ - NO_ARGS; - - if (return_value_used) { - zval *gzip = http_zsep(IS_BOOL, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("gzip")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(gzip, 1, 1); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setCacheControl(string control[, int max_age = 0[, bool must_revalidate = true]]) - Set a custom cache-control header, usually being "private" or "public"; The max_age parameter controls how long the cache entry is valid on the client side. */ -PHP_METHOD(HttpResponse, setCacheControl) -{ - char *ccontrol, *cctl; - int cc_len; - long max_age = 0; - zend_bool must_revalidate = 1; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lb", &ccontrol, &cc_len, &max_age, &must_revalidate)) { - RETURN_FALSE; - } - - if (strcmp(ccontrol, "public") && strcmp(ccontrol, "private") && strcmp(ccontrol, "no-cache")) { - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol); - RETURN_FALSE; - } else { - size_t cctl_len = spprintf(&cctl, 0, "%s,%s max-age=%ld", ccontrol, must_revalidate?" must-revalidate,":"", max_age); - RETVAL_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("cacheControl")-1, cctl, cctl_len TSRMLS_CC)); - efree(cctl); - } -} -/* }}} */ - -/* {{{ proto static string HttpResponse::getCacheControl() - Get current Cache-Control header setting. */ -PHP_METHOD(HttpResponse, getCacheControl) -{ - NO_ARGS; - - if (return_value_used) { - zval *cctl = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("cacheControl")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(cctl, 1, 1); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setContentType(string content_type) - Set the content-type of the sent entity. */ -PHP_METHOD(HttpResponse, setContentType) -{ - char *ctype; - int ctype_len; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ctype_len)) { - RETURN_FALSE; - } - - HTTP_CHECK_CONTENT_TYPE(ctype, RETURN_FALSE); - RETURN_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("contentType")-1, ctype, ctype_len TSRMLS_CC)); -} -/* }}} */ - -/* {{{ proto static string HttpResponse::getContentType() - Get current Content-Type header setting. */ -PHP_METHOD(HttpResponse, getContentType) -{ - NO_ARGS; - - if (return_value_used) { - zval *ctype = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentType")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(ctype, 1, 1); - } -} -/* }}} */ - -/* {{{ proto static string HttpResponse::guessContentType(string magic_file[, int magic_mode = MAGIC_MIME]) - Attempts to guess the content type of supplied payload through libmagic. */ -PHP_METHOD(HttpResponse, guessContentType) -{ -#ifdef HTTP_HAVE_MAGIC - char *magic_file, *ct = NULL; - int magic_file_len; - long magic_mode = MAGIC_MIME; - - RETVAL_FALSE; - SET_EH_THROW_HTTP(); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &magic_file, &magic_file_len, &magic_mode)) { - switch (Z_LVAL_P(*zend_std_get_static_property(THIS_CE, ZEND_STRS("mode")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))) { - case SEND_DATA: - { - zval *data = *zend_std_get_static_property(THIS_CE, ZEND_STRS("data")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC); - ct = http_guess_content_type(magic_file, magic_mode, Z_STRVAL_P(data), Z_STRLEN_P(data), SEND_DATA); - break; - } - - case SEND_RSRC: - { - php_stream *s; - zval *z = *zend_std_get_static_property(THIS_CE, ZEND_STRS("stream")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC); - z->type = IS_RESOURCE; - php_stream_from_zval(s, &z); - ct = http_guess_content_type(magic_file, magic_mode, s, 0, SEND_RSRC); - break; - } - - default: - ct = http_guess_content_type(magic_file, magic_mode, Z_STRVAL_P(*zend_std_get_static_property(THIS_CE, ZEND_STRS("file")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)), 0, -1); - break; - } - if (ct) { - zend_update_static_property_string(THIS_CE, ZEND_STRS("contentType")-1, ct TSRMLS_CC); - RETVAL_STRING(ct, 0); - } - } - SET_EH_NORMAL(); -#else - http_error(HE_THROW, HTTP_E_RUNTIME, "Cannot guess Content-Type; libmagic not available"); - RETURN_FALSE; -#endif -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setContentDisposition(string filename[, bool inline = false]) - Set the Content-Disposition. */ -PHP_METHOD(HttpResponse, setContentDisposition) -{ - char *file, *cd; - int file_len; - size_t cd_len; - zend_bool send_inline = 0; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &file, &file_len, &send_inline)) { - RETURN_FALSE; - } - - cd_len = spprintf(&cd, 0, "%s; filename=\"%s\"", send_inline ? "inline" : "attachment", file); - RETVAL_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("contentDisposition")-1, cd, cd_len TSRMLS_CC)); - efree(cd); -} -/* }}} */ - -/* {{{ proto static string HttpResponse::getContentDisposition() - Get current Content-Disposition setting. */ -PHP_METHOD(HttpResponse, getContentDisposition) -{ - NO_ARGS; - - if (return_value_used) { - zval *cdisp = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentDisposition")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(cdisp, 1, 1); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setETag(string etag) - Set a custom ETag. Use this only if you know what you're doing. */ -PHP_METHOD(HttpResponse, setETag) -{ - char *etag; - int etag_len; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len)) { - RETURN_FALSE; - } - - RETURN_SUCCESS(zend_update_static_property_stringl(THIS_CE, ZEND_STRS("eTag")-1, etag, etag_len TSRMLS_CC)); -} -/* }}} */ - -/* {{{ proto static string HttpResponse::getETag() - Get calculated or previously set custom ETag. */ -PHP_METHOD(HttpResponse, getETag) -{ - NO_ARGS; - - if (return_value_used) { - zval *etag = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("eTag")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(etag, 1, 1); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setLastModified(int timestamp) - Set a custom Last-Modified date. */ -PHP_METHOD(HttpResponse, setLastModified) -{ - long lm; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &lm)) { - RETURN_FALSE; - } - - RETURN_SUCCESS(zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, lm TSRMLS_CC)); -} -/* }}} */ - -/* {{{ proto static int HttpResponse::getLastModified() - Get calculated or previously set custom Last-Modified date. */ -PHP_METHOD(HttpResponse, getLastModified) -{ - NO_ARGS; - - if (return_value_used) { - zval *lmod = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("lastModified")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(lmod, 1, 1); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setThrottleDelay(double seconds) - Sets the throttle delay for use with HttpResponse::setBufferSize(). */ -PHP_METHOD(HttpResponse, setThrottleDelay) -{ - double seconds; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &seconds)) { - RETURN_FALSE; - } - RETURN_SUCCESS(zend_update_static_property_double(THIS_CE, ZEND_STRS("throttleDelay")-1, seconds TSRMLS_CC)); -} -/* }}} */ - -/* {{{ proto static double HttpResponse::getThrottleDelay() - Get the current throttle delay. */ -PHP_METHOD(HttpResponse, getThrottleDelay) -{ - NO_ARGS; - - if (return_value_used) { - zval *tdel = http_zsep(IS_DOUBLE, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("throttleDelay")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(tdel, 1, 1); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setBufferSize(int bytes) - Sets the send buffer size for use with HttpResponse::setThrottleDelay(). */ -PHP_METHOD(HttpResponse, setBufferSize) -{ - long bytes; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &bytes)) { - RETURN_FALSE; - } - RETURN_SUCCESS(zend_update_static_property_long(THIS_CE, ZEND_STRS("bufferSize")-1, bytes TSRMLS_CC)); -} -/* }}} */ - -/* {{{ proto static int HttpResponse::getBufferSize() - Get current buffer size. */ -PHP_METHOD(HttpResponse, getBufferSize) -{ - NO_ARGS; - - if (return_value_used) { - zval *bsize = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("bufferSize")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(bsize, 1, 1); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setData(mixed data) - Set the data to be sent. */ -PHP_METHOD(HttpResponse, setData) -{ - char *etag; - zval *the_data; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &the_data)) { - RETURN_FALSE; - } - if (Z_TYPE_P(the_data) != IS_STRING) { - convert_to_string(the_data); - } - - if ( (SUCCESS != zend_update_static_property(THIS_CE, ZEND_STRS("data")-1, the_data TSRMLS_CC)) || - (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("mode")-1, SEND_DATA TSRMLS_CC))) { - RETURN_FALSE; - } - - zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, http_last_modified(the_data, SEND_DATA) TSRMLS_CC); - if ((etag = http_etag(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), SEND_DATA))) { - zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC); - efree(etag); - } - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto static string HttpResponse::getData() - Get the previously set data to be sent. */ -PHP_METHOD(HttpResponse, getData) -{ - NO_ARGS; - - if (return_value_used) { - zval *the_data = *zend_std_get_static_property(THIS_CE, ZEND_STRS("data")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC); - - RETURN_ZVAL(the_data, 1, 0); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setStream(resource stream) - Set the resource to be sent. */ -PHP_METHOD(HttpResponse, setStream) -{ - char *etag; - zval *the_stream; - php_stream *the_real_stream; - php_stream_statbuf ssb; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &the_stream)) { - RETURN_FALSE; - } - - php_stream_from_zval(the_real_stream, &the_stream); - if (php_stream_stat(the_real_stream, &ssb)) { - RETURN_FALSE; - } - - if ( (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("stream")-1, Z_LVAL_P(the_stream) TSRMLS_CC)) || - (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("mode")-1, SEND_RSRC TSRMLS_CC))) { - RETURN_FALSE; - } - zend_list_addref(Z_LVAL_P(the_stream)); - - zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, http_last_modified(the_real_stream, SEND_RSRC) TSRMLS_CC); - if ((etag = http_etag(the_real_stream, 0, SEND_RSRC))) { - zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC); - efree(etag); - } - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto static resource HttpResponse::getStream() - Get the previously set resource to be sent. */ -PHP_METHOD(HttpResponse, getStream) -{ - NO_ARGS; - - if (return_value_used) { - zval *stream = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("stream")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_RESOURCE(Z_LVAL_P(stream)); - zval_ptr_dtor(&stream); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::setFile(string file) - Set the file to be sent. */ -PHP_METHOD(HttpResponse, setFile) -{ - char *the_file, *etag; - int file_len; - php_stream_statbuf ssb; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &the_file, &file_len)) { - RETURN_FALSE; - } - - if (php_stream_stat_path(the_file, &ssb)) { - RETURN_FALSE; - } - - if ( (SUCCESS != zend_update_static_property_stringl(THIS_CE, ZEND_STRS("file")-1, the_file, file_len TSRMLS_CC)) || - (SUCCESS != zend_update_static_property_long(THIS_CE, ZEND_STRS("mode")-1, -1 TSRMLS_CC))) { - RETURN_FALSE; - } - - zend_update_static_property_long(THIS_CE, ZEND_STRS("lastModified")-1, http_last_modified(the_file, -1) TSRMLS_CC); - if ((etag = http_etag(the_file, 0, -1))) { - zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC); - efree(etag); - } - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto static string HttpResponse::getFile() - Get the previously set file to be sent. */ -PHP_METHOD(HttpResponse, getFile) -{ - NO_ARGS; - - if (return_value_used) { - zval *file = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("file")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_ZVAL(file, 1, 1); - } -} -/* }}} */ - -/* {{{ proto static bool HttpResponse::send([bool clean_ob = true]) - Finally send the entity. */ -PHP_METHOD(HttpResponse, send) -{ - zval *sent; - zend_bool clean_ob = 1; - - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean_ob)) { - RETURN_FALSE; - } - - HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); - - sent = *zend_std_get_static_property(THIS_CE, ZEND_STRS("sent")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC); - if (Z_LVAL_P(sent)) { - http_error(HE_WARNING, HTTP_E_RESPONSE, "Cannot send HttpResponse, response has already been sent"); - RETURN_FALSE; - } else { - Z_LVAL_P(sent) = 1; - } - - /* capture mode */ - if (i_zend_is_true(*zend_std_get_static_property(THIS_CE, ZEND_STRS("catch")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))) { - zval *zetag, *the_data; - - MAKE_STD_ZVAL(the_data); -#ifdef PHP_OUTPUT_NEWAPI - php_output_get_contents(the_data TSRMLS_CC); -#else - php_ob_get_buffer(the_data TSRMLS_CC); -#endif - zend_update_static_property(THIS_CE, ZEND_STRS("data")-1, the_data TSRMLS_CC); - ZVAL_LONG(*zend_std_get_static_property(THIS_CE, ZEND_STRS("mode")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC), SEND_DATA); - - zetag = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("eTag")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - if (!Z_STRLEN_P(zetag)) { - char *etag = http_etag(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), SEND_DATA); - if (etag) { - zend_update_static_property_string(THIS_CE, ZEND_STRS("eTag")-1, etag TSRMLS_CC); - efree(etag); - } - } - zval_ptr_dtor(&the_data); - zval_ptr_dtor(&zetag); - - clean_ob = 1; - } - - if (clean_ob) { - /* interrupt on-the-fly etag generation */ - HTTP_G->etag.started = 0; - /* discard previous output buffers */ -#ifdef PHP_OUTPUT_NEWAPI - php_output_discard_all(TSRMLS_C); -#else - php_end_ob_buffers(0 TSRMLS_CC); -#endif - } - - /* caching */ - if (i_zend_is_true(*zend_std_get_static_property(THIS_CE, ZEND_STRS("cache")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))) { - zval *cctl, *etag, *lmod; - - lmod = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("lastModified")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - etag = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("eTag")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - cctl = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("cacheControl")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - - if (Z_LVAL_P(lmod) || Z_STRLEN_P(etag)) { - if (Z_STRLEN_P(cctl)) { - http_send_cache_control(Z_STRVAL_P(cctl), Z_STRLEN_P(cctl)); - } else { - http_send_cache_control(HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL)); - } - if (Z_STRLEN_P(etag)) { - http_send_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag)); - } - if (Z_LVAL_P(lmod)) { - http_send_last_modified(Z_LVAL_P(lmod)); - } - } - - zval_ptr_dtor(&etag); - zval_ptr_dtor(&lmod); - zval_ptr_dtor(&cctl); - } - - /* content type */ - { - zval *ctype = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentType")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - if (Z_STRLEN_P(ctype)) { - http_send_content_type(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype)); - } else { - char *ctypes = INI_STR("default_mimetype"); - size_t ctlen = ctypes ? strlen(ctypes) : 0; - - if (ctlen) { - http_send_content_type(ctypes, ctlen); - } else { - http_send_content_type("application/x-octetstream", lenof("application/x-octetstream")); - } - } - zval_ptr_dtor(&ctype); - } - - /* content disposition */ - { - zval *cd = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("contentDisposition")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - if (Z_STRLEN_P(cd)) { - http_send_header_ex("Content-Disposition", lenof("Content-Disposition"), Z_STRVAL_P(cd), Z_STRLEN_P(cd), 1, NULL); - } - zval_ptr_dtor(&cd); - } - - /* throttling */ - { - zval *bsize = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("bufferSize")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - zval *delay = http_zsep(IS_DOUBLE, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("throttleDelay")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - HTTP_G->send.buffer_size = Z_LVAL_P(bsize); - HTTP_G->send.throttle_delay = Z_DVAL_P(delay); - zval_ptr_dtor(&bsize); - zval_ptr_dtor(&delay); - } - - /* gzip */ - HTTP_G->send.deflate.response = i_zend_is_true(*zend_std_get_static_property(THIS_CE, ZEND_STRS("gzip")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC)); - - /* send */ - switch (Z_LVAL_P(*zend_std_get_static_property(THIS_CE, ZEND_STRS("mode")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))) { - case SEND_DATA: - { - zval *zdata = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("data")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata))); - zval_ptr_dtor(&zdata); - return; - } - - case SEND_RSRC: - { - php_stream *the_real_stream; - zval *the_stream = http_zsep(IS_LONG, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("stream")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - the_stream->type = IS_RESOURCE; - php_stream_from_zval(the_real_stream, &the_stream); - RETVAL_SUCCESS(http_send_stream(the_real_stream)); - zval_ptr_dtor(&the_stream); - return; - } - - default: - { - zval *file = http_zsep(IS_STRING, *(zend_std_get_static_property(THIS_CE, ZEND_STRS("file")-1, 0 ZEND_LITERAL_NIL_CC TSRMLS_CC))); - RETVAL_SUCCESS(http_send_file(Z_STRVAL_P(file))); - zval_ptr_dtor(&file); - return; - } - } -} -/* }}} */ - -/* {{{ proto static void HttpResponse::capture() - Capture script output. - */ -PHP_METHOD(HttpResponse, capture) -{ - NO_ARGS; - - HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); - - zend_update_static_property_long(THIS_CE, ZEND_STRS("catch")-1, 1 TSRMLS_CC); -#ifdef PHP_OUTPUT_NEWAPI - php_output_discard_all(TSRMLS_C); - php_output_start_default(TSRMLS_C); -#else - php_end_ob_buffers(0 TSRMLS_CC); - php_start_ob_buffer(NULL, 0, 0 TSRMLS_CC); -#endif - - /* register shutdown function */ - { - zval func, retval, arg, *argp[1]; - - INIT_PZVAL(&arg); - INIT_PZVAL(&func); - INIT_PZVAL(&retval); - ZVAL_STRINGL(&func, "register_shutdown_function", lenof("register_shutdown_function"), 0); - - array_init(&arg); - add_next_index_stringl(&arg, "HttpResponse", lenof("HttpResponse"), 1); - add_next_index_stringl(&arg, "send", lenof("send"), 1); - argp[0] = &arg; - call_user_function(EG(function_table), NULL, &func, &retval, 1, argp TSRMLS_CC); - zval_dtor(&arg); - } -} -/* }}} */ - -#endif /* ZEND_ENGINE_2 && !WONKY */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_send_api.c b/http_send_api.c deleted file mode 100644 index 1082e29..0000000 --- a/http_send_api.c +++ /dev/null @@ -1,611 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#define HTTP_WANT_ZLIB -#define HTTP_WANT_MAGIC -#include "php_http.h" - -#include "php_streams.h" - -#include "php_http_api.h" -#include "php_http_cache_api.h" -#include "php_http_date_api.h" -#include "php_http_encoding_api.h" -#include "php_http_headers_api.h" -#include "php_http_send_api.h" - -/* {{{ http_flush() */ -#define http_flush(d, l) _http_flush(NULL, (d), (l) TSRMLS_CC) -static inline void _http_flush(void *nothing, const char *data, size_t data_len TSRMLS_DC) -{ - PHPWRITE(data, data_len); - /* we really only need to flush when throttling is enabled, - because we push the data as fast as possible anyway if not */ - if (HTTP_G->send.throttle_delay >= HTTP_DIFFSEC) { -#if defined(PHP_VERSION_ID) && (PHP_VERSION_ID >= 50399) - php_output_end_all(TSRMLS_C); -#else - if (OG(ob_nesting_level)) { - php_end_ob_buffer(1, 1 TSRMLS_CC); - } - if (!OG(implicit_flush)) { - sapi_flush(TSRMLS_C); - } -#endif - http_sleep(HTTP_G->send.throttle_delay); - } -} -/* }}} */ - -/* {{{ http_send_response_start */ -#define http_send_response_start(b, cl) _http_send_response_start((b), (cl) TSRMLS_CC) -static inline void _http_send_response_start(void **buffer, size_t content_length TSRMLS_DC) -{ - int encoding; - - if ((encoding = http_encoding_response_start(content_length, 0))) { -#ifdef HTTP_HAVE_ZLIB - *((http_encoding_stream **) buffer) = http_encoding_deflate_stream_init(NULL, - (encoding == HTTP_ENCODING_GZIP) ? - HTTP_DEFLATE_TYPE_GZIP : HTTP_DEFLATE_TYPE_ZLIB); -#endif - } - /* flush headers */ - sapi_flush(TSRMLS_C); -} -/* }}} */ - -/* {{{ http_send_response_data_plain */ -#define http_send_response_data_plain(b, d, dl) _http_send_response_data_plain((b), (d), (dl) TSRMLS_CC) -static inline void _http_send_response_data_plain(void **buffer, const char *data, size_t data_len TSRMLS_DC) -{ - if (HTTP_G->send.deflate.response && HTTP_G->send.deflate.encoding) { -#ifdef HTTP_HAVE_ZLIB - char *encoded; - size_t encoded_len; - http_encoding_stream *s = *((http_encoding_stream **) buffer); - - http_encoding_deflate_stream_update(s, data, data_len, &encoded, &encoded_len); - if (HTTP_G->send.buffer_size) { - phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, HTTP_G->send.buffer_size, _http_flush, NULL TSRMLS_CC); - } else { - http_flush(encoded, encoded_len); - } - efree(encoded); -#else - http_error(HE_ERROR, HTTP_E_RESPONSE, "Attempt to send GZIP response despite being able to do so; please report this bug"); -#endif - } else if (HTTP_G->send.buffer_size) { - phpstr_chunked_output((phpstr **) buffer, data, data_len, HTTP_G->send.buffer_size, _http_flush, NULL TSRMLS_CC); - } else { - http_flush(data, data_len); - } -} -/* }}} */ - -/* {{{ http_send_response_data_fetch */ -#define http_send_response_data_fetch(b, d, l, m, s, e) _http_send_response_data_fetch((b), (d), (l), (m), (s), (e) TSRMLS_CC) -static inline void _http_send_response_data_fetch(void **buffer, const void *data, size_t data_len, http_send_mode mode, size_t begin, size_t end TSRMLS_DC) -{ - long bsz, got, len = end - begin; - - if (!(bsz = HTTP_G->send.buffer_size)) { - bsz = HTTP_SENDBUF_SIZE; - } - - switch (mode) { - case SEND_RSRC: { - php_stream *s = (php_stream *) data; - if (SUCCESS == php_stream_seek(s, begin, SEEK_SET)) { - char *buf = emalloc(bsz); - - while (len > 0) { - got = php_stream_read(s, buf, MIN(len, bsz)); - http_send_response_data_plain(buffer, buf, got); - len -= got; - } - - efree(buf); - } - break; - } - case SEND_DATA: { - const char *buf = ((const char *) data) + begin; - while (len > 0) { - got = MIN(len, bsz); - http_send_response_data_plain(buffer, buf, got); - len -= got; - buf += got; - } - break; - } - EMPTY_SWITCH_DEFAULT_CASE(); - } -} -/* }}} */ - -/* {{{ http_send_response_finish */ -#define http_send_response_finish(b) _http_send_response_finish((b) TSRMLS_CC) -static inline void _http_send_response_finish(void **buffer TSRMLS_DC) -{ - if (HTTP_G->send.deflate.response && HTTP_G->send.deflate.encoding) { -#ifdef HTTP_HAVE_ZLIB - char *encoded = NULL; - size_t encoded_len = 0; - http_encoding_stream *s = *((http_encoding_stream **) buffer); - - http_encoding_deflate_stream_finish(s, &encoded, &encoded_len); - if (HTTP_G->send.buffer_size) { - phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, 0, _http_flush, NULL TSRMLS_CC); - } else { - http_flush(encoded, encoded_len); - } - http_encoding_deflate_stream_free(&s); - STR_FREE(encoded); -#else - http_error(HE_ERROR, HTTP_E_RESPONSE, "Attempt to send GZIP response despite being able to do so; please report this bug"); -#endif - } else if (HTTP_G->send.buffer_size) { - phpstr_chunked_output((phpstr **) buffer, NULL, 0, 0, _http_flush, NULL TSRMLS_CC); - } -} -/* }}} */ - -/* {{{ */ -PHP_MINIT_FUNCTION(http_send) -{ - HTTP_LONG_CONSTANT("HTTP_REDIRECT", HTTP_REDIRECT); - HTTP_LONG_CONSTANT("HTTP_REDIRECT_PERM", HTTP_REDIRECT_PERM); - HTTP_LONG_CONSTANT("HTTP_REDIRECT_FOUND", HTTP_REDIRECT_FOUND); - HTTP_LONG_CONSTANT("HTTP_REDIRECT_POST", HTTP_REDIRECT_POST); - HTTP_LONG_CONSTANT("HTTP_REDIRECT_PROXY", HTTP_REDIRECT_PROXY); - HTTP_LONG_CONSTANT("HTTP_REDIRECT_TEMP", HTTP_REDIRECT_TEMP); - - return SUCCESS; -} -/* }}} */ - -/* {{{ http_find_header */ -typedef struct { - const char *h; - size_t l; -} http_response_header_t; - -static int http_find_header(void *data, void *arg) -{ - http_response_header_t *h = arg; - sapi_header_struct *s = data; - - return (!strncasecmp(s->header, h->h, h->l)) && s->header[h->l] == ':'; -} -/* }}} */ - -/* {{{ void http_hide_header(char *) */ -PHP_HTTP_API void _http_hide_header_ex(const char *name, size_t name_len TSRMLS_DC) -{ - http_response_header_t h = {name, name_len}; - zend_llist_del_element(&SG(sapi_headers).headers, (void *) &h, http_find_header); -} -/* }}} */ - -/* {{{ void http_send_header_zval(char*, zval **, zend_bool) */ -PHP_HTTP_API void _http_send_header_zval_ex(const char *name, size_t name_len, zval **val, zend_bool replace TSRMLS_DC) -{ - if (!val || !*val || Z_TYPE_PP(val) == IS_NULL || (Z_TYPE_PP(val) == IS_STRING && !Z_STRLEN_PP(val))) { - http_hide_header_ex(name, name_len); - } else if (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT) { - zend_bool first = replace; - zval **data_ptr; - HashPosition pos; - - FOREACH_HASH_VAL(pos, HASH_OF(*val), data_ptr) { - zval *data = http_zsep(IS_STRING, *data_ptr); - - http_send_header_ex(name, name_len, Z_STRVAL_P(data), Z_STRLEN_P(data), first, NULL); - zval_ptr_dtor(&data); - first = 0; - } - } else { - zval *data = http_zsep(IS_STRING, *val); - - http_send_header_ex(name, name_len, Z_STRVAL_P(data), Z_STRLEN_P(data), replace, NULL); - zval_ptr_dtor(&data); - } -} -/* }}} */ - -/* {{{ STATUS http_send_header(char *, char *, zend_bool) */ -PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace, char **sent_header TSRMLS_DC) -{ - STATUS ret; - - if (value && value_len) { - size_t header_len = sizeof(": ") + name_len + value_len + 1; - char *header = emalloc(header_len + 1); - - header[header_len] = '\0'; - header_len = snprintf(header, header_len, "%s: %s", name, value); - ret = http_send_header_string_ex(header, header_len, replace); - if (sent_header) { - *sent_header = header; - } else { - efree(header); - } - } else { - http_hide_header_ex(name, name_len); - ret = SUCCESS; - } - return ret; -} -/* }}} */ - -/* {{{ STATUS http_send_status_header(int, char *) */ -PHP_HTTP_API STATUS _http_send_status_header_ex(int status, const char *header, size_t header_len, zend_bool replace TSRMLS_DC) -{ - STATUS ret; - sapi_header_line h = {(char *) header, header_len, status}; - if (SUCCESS != (ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, &h TSRMLS_CC))) { - http_error_ex(HE_WARNING, HTTP_E_HEADER, "Could not send header: %s (%d)", header, status); - } - return ret; -} -/* }}} */ - -/* {{{ STATUS http_send_last_modified(int) */ -PHP_HTTP_API STATUS _http_send_last_modified_ex(time_t t, char **sent_header TSRMLS_DC) -{ - STATUS ret; - char *date = http_date(t); - - if (!date) { - return FAILURE; - } - - ret = http_send_header_ex("Last-Modified", lenof("Last-Modified"), date, strlen(date), 1, sent_header); - efree(date); - - /* remember */ - HTTP_G->send.last_modified = t; - - return ret; -} -/* }}} */ - -/* {{{ STATUS http_send_etag(char *, size_t) */ -PHP_HTTP_API STATUS _http_send_etag_ex(const char *etag, size_t etag_len, char **sent_header TSRMLS_DC) -{ - STATUS status; - char *etag_header; - size_t etag_header_len; - - if (!etag_len){ - http_error_ex(HE_WARNING, HTTP_E_HEADER, "Attempt to send empty ETag (previous: %s)\n", HTTP_G->send.unquoted_etag); - return FAILURE; - } - - etag_header_len = spprintf(&etag_header, 0, "ETag: \"%s\"", etag); - status = http_send_header_string_ex(etag_header, etag_header_len, 1); - - /* remember */ - STR_SET(HTTP_G->send.unquoted_etag, estrndup(etag, etag_len)); - - if (sent_header) { - *sent_header = etag_header; - } else { - efree(etag_header); - } - - return status; -} -/* }}} */ - -/* {{{ STATUS http_send_content_type(char *, size_t) */ -PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_len TSRMLS_DC) -{ - HTTP_CHECK_CONTENT_TYPE(content_type, return FAILURE); - - /* remember for multiple ranges */ - STR_FREE(HTTP_G->send.content_type); - HTTP_G->send.content_type = estrndup(content_type, ct_len); - - return http_send_header_ex("Content-Type", lenof("Content-Type"), content_type, ct_len, 1, NULL); -} -/* }}} */ - -/* {{{ STATUS http_send_content_disposition(char *, size_t, zend_bool) */ -PHP_HTTP_API STATUS _http_send_content_disposition(const char *filename, size_t f_len, zend_bool send_inline TSRMLS_DC) -{ - STATUS status; - char *cd_header; - - if (send_inline) { - cd_header = ecalloc(1, sizeof("Content-Disposition: inline; filename=\"\"") + f_len); - sprintf(cd_header, "Content-Disposition: inline; filename=\"%s\"", filename); - } else { - cd_header = ecalloc(1, sizeof("Content-Disposition: attachment; filename=\"\"") + f_len); - sprintf(cd_header, "Content-Disposition: attachment; filename=\"%s\"", filename); - } - - status = http_send_header_string(cd_header); - efree(cd_header); - return status; -} -/* }}} */ - -/* {{{ STATUS http_send(void *, size_t, http_send_mode) */ -PHP_HTTP_API STATUS _http_send_ex(const void *data_ptr, size_t data_size, http_send_mode data_mode, zend_bool no_cache TSRMLS_DC) -{ - void *s = NULL; - HashTable ranges; - http_range_status range_status; - - if (!data_ptr) { - return FAILURE; - } - if (!data_size) { - return SUCCESS; - } - - /* enable partial dl and resume */ - http_send_header_string("Accept-Ranges: bytes"); - - zend_hash_init(&ranges, 0, NULL, ZVAL_PTR_DTOR, 0); - range_status = http_get_request_ranges(&ranges, data_size); - - switch (range_status) { - case RANGE_ERR: - { - zend_hash_destroy(&ranges); - http_send_status(416); - return FAILURE; - } - case RANGE_OK: - { - /* Range Request - only send ranges if entity hasn't changed */ - if ( http_got_server_var("HTTP_IF_RANGE") && - !http_match_etag("HTTP_IF_RANGE", HTTP_G->send.unquoted_etag) && - !http_match_last_modified("HTTP_IF_RANGE", HTTP_G->send.last_modified)) { - /* fallthrough to send full entity with 200 Ok */ - no_cache = 1; - } else if ( !http_match_etag_ex("HTTP_IF_MATCH", HTTP_G->send.unquoted_etag, 0) || - !http_match_last_modified_ex("HTTP_IF_UNMODIFIED_SINCE", HTTP_G->send.last_modified, 0) || - !http_match_last_modified_ex("HTTP_UNLESS_MODIFIED_SINCE", HTTP_G->send.last_modified, 0)) { - /* 412 Precondition failed */ - zend_hash_destroy(&ranges); - http_send_status(412); - return FAILURE; - } else if (zend_hash_num_elements(&ranges) == 1) { - /* single range */ - zval **range, **begin, **end; - - if ( SUCCESS != zend_hash_index_find(&ranges, 0, (void *) &range) || - SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(range), 0, (void *) &begin) || - SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(range), 1, (void *) &end)) { - /* this should never happen */ - zend_hash_destroy(&ranges); - http_send_status(500); - return FAILURE; - } else { - phpstr header; - - phpstr_init(&header); - phpstr_appendf(&header, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_PP(begin), Z_LVAL_PP(end), data_size); - phpstr_fix(&header); - http_send_status_header_ex(206, PHPSTR_VAL(&header), PHPSTR_LEN(&header), 1); - phpstr_dtor(&header); - http_send_response_start(&s, Z_LVAL_PP(end)-Z_LVAL_PP(begin)+1); - http_send_response_data_fetch(&s, data_ptr, data_size, data_mode, Z_LVAL_PP(begin), Z_LVAL_PP(end) + 1); - http_send_response_finish(&s); - zend_hash_destroy(&ranges); - return SUCCESS; - } - } else { - /* multi range */ - HashPosition pos; - zval **range, **begin, **end; - const char *content_type = HTTP_G->send.content_type; - char boundary_str[32]; - size_t boundary_len; - phpstr header, preface; - - boundary_len = http_boundary(boundary_str, sizeof(boundary_str)); - phpstr_init(&header); - phpstr_appendf(&header, "Content-Type: multipart/byteranges; boundary=%s", boundary_str); - phpstr_fix(&header); - http_send_status_header_ex(206, PHPSTR_VAL(&header), PHPSTR_LEN(&header), 1); - phpstr_dtor(&header); - http_send_response_start(&s, 0); - - if (!content_type) { - content_type = "application/x-octetstream"; - } - - phpstr_init(&preface); - FOREACH_HASH_VAL(pos, &ranges, range) { - if ( SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(range), 0, (void *) &begin) && - SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(range), 1, (void *) &end)) { - -#define HTTP_RANGE_PREFACE \ - HTTP_CRLF "--%s" \ - HTTP_CRLF "Content-Type: %s" \ - HTTP_CRLF "Content-Range: bytes %ld-%ld/%zu" \ - HTTP_CRLF HTTP_CRLF - - phpstr_appendf(&preface, HTTP_RANGE_PREFACE, boundary_str, content_type, Z_LVAL_PP(begin), Z_LVAL_PP(end), data_size); - phpstr_fix(&preface); - http_send_response_data_plain(&s, PHPSTR_VAL(&preface), PHPSTR_LEN(&preface)); - phpstr_reset(&preface); - http_send_response_data_fetch(&s, data_ptr, data_size, data_mode, Z_LVAL_PP(begin), Z_LVAL_PP(end) + 1); - } - } - phpstr_dtor(&preface); - - http_send_response_data_plain(&s, HTTP_CRLF "--", lenof(HTTP_CRLF "--")); - http_send_response_data_plain(&s, boundary_str, boundary_len); - http_send_response_data_plain(&s, "--", lenof("--")); - - http_send_response_finish(&s); - zend_hash_destroy(&ranges); - return SUCCESS; - } - } - case RANGE_NO: - { - zend_hash_destroy(&ranges); - - /* send 304 Not Modified if etag matches - DON'T return on ETag generation failure */ - if (!no_cache && (http_interrupt_ob_etaghandler() || (HTTP_G->send.unquoted_etag != NULL))) { - char *etag = NULL; - - if (HTTP_G->send.unquoted_etag) { - etag = estrdup(HTTP_G->send.unquoted_etag); - } - - if (etag || (etag = http_etag(data_ptr, data_size, data_mode))) { - char *sent_header = NULL; - - http_send_etag_ex(etag, strlen(etag), &sent_header); - if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) { - return http_exit_ex(304, sent_header, NULL, 0); - } else { - STR_FREE(sent_header); - /* no caching for Last-Modified if ETags really don't match */ - no_cache = http_got_server_var("HTTP_IF_NONE_MATCH"); - } - efree(etag); - } - } - - /* send 304 Not Modified if last modified matches */ - if (!no_cache && HTTP_G->send.last_modified && http_match_last_modified("HTTP_IF_MODIFIED_SINCE", HTTP_G->send.last_modified)) { - char *sent_header = NULL; - http_send_last_modified_ex(HTTP_G->send.last_modified, &sent_header); - return http_exit_ex(304, sent_header, NULL, 0); - } - - /* send full response */ - http_send_response_start(&s, data_size); - http_send_response_data_fetch(&s, data_ptr, data_size, data_mode, 0, data_size); - http_send_response_finish(&s); - return SUCCESS; - } - } - return FAILURE; -} -/* }}} */ - -/* {{{ STATUS http_send_stream(php_stream *) */ -PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *file, zend_bool close_stream, zend_bool no_cache TSRMLS_DC) -{ - STATUS status; - php_stream_statbuf ssb; - int orig_flags; - - if ((!file) || php_stream_stat(file, &ssb)) { - char *defct = sapi_get_default_content_type(TSRMLS_C); - - http_hide_header("Content-Disposition"); - http_send_content_type(defct, strlen(defct)); - http_error(HE_WARNING, HTTP_E_RESPONSE, "File not found; stat failed"); - STR_FREE(defct); - - if (HTTP_G->send.not_found_404) { - http_exit_ex(404, NULL, estrdup("File not found\n"), 0); - } - return FAILURE; - } - - orig_flags = file->flags; - file->flags |= PHP_STREAM_FLAG_NO_BUFFER; - status = http_send_ex(file, ssb.sb.st_size, SEND_RSRC, no_cache); - file->flags = orig_flags; - - if (close_stream) { - php_stream_close(file); - } - - return status; -} -/* }}} */ - -/* {{{ char *http_guess_content_type(char *magic_file, long magic_mode, void *data, size_t size, http_send_mode mode) */ -PHP_HTTP_API char *_http_guess_content_type(const char *magicfile, long magicmode, void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC) -{ - char *ct = NULL; - -#ifdef HTTP_HAVE_MAGIC - struct magic_set *magic = NULL; - - HTTP_CHECK_OPEN_BASEDIR(magicfile, return NULL); - - if (!data_ptr) { - http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Supplied payload is empty"); - } else if (!(magic = magic_open(magicmode &~ MAGIC_MIME))) { - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid magic mode: %ld", magicmode); - } else if (-1 == magic_load(magic, magicfile)) { - http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Failed to load magic database '%s' (%s)", magicfile, magic_error(magic)); - } else { - const char *ctype = NULL; - - magic_setflags(magic, magicmode); - - switch (data_mode) { - case SEND_RSRC: - { - char *buffer; - size_t b_len; - - b_len = php_stream_copy_to_mem(data_ptr, &buffer, 65536, 0); - ctype = magic_buffer(magic, buffer, b_len); - efree(buffer); - break; - } - - case SEND_DATA: - ctype = magic_buffer(magic, data_ptr, data_len); - break; - - default: - HTTP_CHECK_OPEN_BASEDIR(data_ptr, magic_close(magic); return NULL); - ctype = magic_file(magic, data_ptr); - break; - } - - if (ctype) { - ct = estrdup(ctype); - } else { - http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Failed to guess Content-Type: %s", magic_error(magic)); - } - } - if (magic) { - magic_close(magic); - } -#else - http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot guess Content-Type; libmagic not available"); -#endif - - return ct; -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ - diff --git a/http_url_api.c b/http_url_api.c deleted file mode 100644 index 8a70b0f..0000000 --- a/http_url_api.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#define HTTP_WANT_SAPI -#define HTTP_WANT_NETDB -#include "php_http.h" - -#include "zend_ini.h" -#include "php_output.h" -#include "ext/standard/php_string.h" - -#include "php_http_api.h" -#include "php_http_querystring_api.h" -#include "php_http_url_api.h" - -static inline char *localhostname(void) -{ - char hostname[1024] = {0}; - -#ifdef PHP_WIN32 - if (SUCCESS == gethostname(hostname, lenof(hostname))) { - return estrdup(hostname); - } -#elif defined(HAVE_GETHOSTNAME) - if (SUCCESS == gethostname(hostname, lenof(hostname))) { -# if defined(HAVE_GETDOMAINNAME) - size_t hlen = strlen(hostname); - if (hlen <= lenof(hostname) - lenof("(none)")) { - hostname[hlen++] = '.'; - if (SUCCESS == getdomainname(&hostname[hlen], lenof(hostname) - hlen)) { - if (!strcmp(&hostname[hlen], "(none)")) { - hostname[hlen - 1] = '\0'; - } - return estrdup(hostname); - } - } -# endif - if (strcmp(hostname, "(none)")) { - return estrdup(hostname); - } - } -#endif - return estrndup("localhost", lenof("localhost")); -} - -PHP_MINIT_FUNCTION(http_url) -{ - HTTP_LONG_CONSTANT("HTTP_URL_REPLACE", HTTP_URL_REPLACE); - HTTP_LONG_CONSTANT("HTTP_URL_JOIN_PATH", HTTP_URL_JOIN_PATH); - HTTP_LONG_CONSTANT("HTTP_URL_JOIN_QUERY", HTTP_URL_JOIN_QUERY); - HTTP_LONG_CONSTANT("HTTP_URL_STRIP_USER", HTTP_URL_STRIP_USER); - HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PASS", HTTP_URL_STRIP_PASS); - HTTP_LONG_CONSTANT("HTTP_URL_STRIP_AUTH", HTTP_URL_STRIP_AUTH); - HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PORT", HTTP_URL_STRIP_PORT); - HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PATH", HTTP_URL_STRIP_PATH); - HTTP_LONG_CONSTANT("HTTP_URL_STRIP_QUERY", HTTP_URL_STRIP_QUERY); - HTTP_LONG_CONSTANT("HTTP_URL_STRIP_FRAGMENT", HTTP_URL_STRIP_FRAGMENT); - HTTP_LONG_CONSTANT("HTTP_URL_STRIP_ALL", HTTP_URL_STRIP_ALL); - HTTP_LONG_CONSTANT("HTTP_URL_FROM_ENV", HTTP_URL_FROM_ENV); - return SUCCESS; -} - -PHP_HTTP_API char *_http_absolute_url_ex(const char *url, int flags TSRMLS_DC) -{ - char *abs = NULL; - php_url *purl = NULL; - - if (url) { - purl = php_url_parse(abs = estrdup(url)); - STR_SET(abs, NULL); - if (!purl) { - http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", url); - return NULL; - } - } - - http_build_url(flags, purl, NULL, NULL, &abs, NULL); - - if (purl) { - php_url_free(purl); - } - - return abs; -} - -/* {{{ void http_build_url(int flags, const php_url *, const php_url *, php_url **, char **, size_t *) */ -PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC) -{ -#if defined(HAVE_GETSERVBYPORT) || defined(HAVE_GETSERVBYNAME) - struct servent *se; -#endif - php_url *url = ecalloc(1, sizeof(php_url)); - -#define __URLSET(u,n) \ - ((u)&&(u)->n) -#define __URLCPY(n) \ - url->n = __URLSET(new_url,n) ? estrdup(new_url->n) : (__URLSET(old_url,n) ? estrdup(old_url->n) : NULL) - - if (!(flags & HTTP_URL_STRIP_PORT)) { - url->port = __URLSET(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0); - } - if (!(flags & HTTP_URL_STRIP_USER)) { - __URLCPY(user); - } - if (!(flags & HTTP_URL_STRIP_PASS)) { - __URLCPY(pass); - } - - __URLCPY(scheme); - __URLCPY(host); - - if (!(flags & HTTP_URL_STRIP_PATH)) { - if ((flags & HTTP_URL_JOIN_PATH) && __URLSET(old_url, path) && __URLSET(new_url, path) && *new_url->path != '/') { - size_t old_path_len = strlen(old_url->path), new_path_len = strlen(new_url->path); - - url->path = ecalloc(1, old_path_len + new_path_len + 1 + 1); - - strcat(url->path, old_url->path); - if (url->path[old_path_len - 1] != '/') { - php_dirname(url->path, old_path_len); - strcat(url->path, "/"); - } - strcat(url->path, new_url->path); - } else { - __URLCPY(path); - } - } - if (!(flags & HTTP_URL_STRIP_QUERY)) { - if ((flags & HTTP_URL_JOIN_QUERY) && __URLSET(new_url, query) && __URLSET(old_url, query)) { - zval qarr, qstr; - - INIT_PZVAL(&qstr); - INIT_PZVAL(&qarr); - array_init(&qarr); - - ZVAL_STRING(&qstr, old_url->query, 0); - http_querystring_modify(&qarr, &qstr); - ZVAL_STRING(&qstr, new_url->query, 0); - http_querystring_modify(&qarr, &qstr); - - ZVAL_NULL(&qstr); - http_querystring_update(&qarr, &qstr); - url->query = Z_STRVAL(qstr); - zval_dtor(&qarr); - } else { - __URLCPY(query); - } - } - if (!(flags & HTTP_URL_STRIP_FRAGMENT)) { - __URLCPY(fragment); - } - - if (!url->scheme) { - if (flags & HTTP_URL_FROM_ENV) { - zval *https = http_get_server_var("HTTPS", 1); - if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) { - url->scheme = estrndup("https", lenof("https")); - } else switch (url->port) { - case 443: - url->scheme = estrndup("https", lenof("https")); - break; - -#ifndef HAVE_GETSERVBYPORT - default: -#endif - case 80: - case 0: - url->scheme = estrndup("http", lenof("http")); - break; - -#ifdef HAVE_GETSERVBYPORT - default: - if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) { - url->scheme = estrdup(se->s_name); - } else { - url->scheme = estrndup("http", lenof("http")); - } - break; -#endif - } - } else { - url->scheme = estrndup("http", lenof("http")); - } - } - - if (!url->host) { - if (flags & HTTP_URL_FROM_ENV) { - zval *zhost; - - if ((((zhost = http_get_server_var("HTTP_HOST", 1)) || - (zhost = http_get_server_var("SERVER_NAME", 1)))) && Z_STRLEN_P(zhost)) { - url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost)); - } else { - url->host = localhostname(); - } - } else { - url->host = estrndup("localhost", lenof("localhost")); - } - } - - if (!url->path) { - if ((flags & HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) { - const char *q = strchr(SG(request_info).request_uri, '?'); - - if (q) { - url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri); - } else { - url->path = estrdup(SG(request_info).request_uri); - } - } else { - url->path = estrndup("/", 1); - } - } else if (url->path[0] != '/') { - if ((flags & HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) { - size_t ulen = strlen(SG(request_info).request_uri); - size_t plen = strlen(url->path); - char *path; - - if (SG(request_info).request_uri[ulen-1] != '/') { - for (--ulen; ulen && SG(request_info).request_uri[ulen - 1] != '/'; --ulen); - } - - path = emalloc(ulen + plen + 1); - memcpy(path, SG(request_info).request_uri, ulen); - memcpy(path + ulen, url->path, plen); - path[ulen + plen] = '\0'; - STR_SET(url->path, path); - } else { - size_t plen = strlen(url->path); - char *path = emalloc(plen + 1 + 1); - - path[0] = '/'; - memcpy(&path[1], url->path, plen + 1); - STR_SET(url->path, path); - } - } - /* replace directory references if path is not a single slash */ - if (url->path[0] && (url->path[0] != '/' || url->path[1])) { - char *ptr, *end = url->path + strlen(url->path) + 1; - - for (ptr = strstr(url->path, "/."); ptr; ptr = strstr(ptr, "/.")) { - switch (ptr[2]) { - case '\0': - ptr[1] = '\0'; - break; - - case '/': - memmove(&ptr[1], &ptr[3], end - &ptr[3]); - break; - - case '.': - if (ptr[3] == '/') { - char *pos = &ptr[4]; - while (ptr != url->path) { - if (*--ptr == '/') { - break; - } - } - memmove(&ptr[1], pos, end - pos); - break; - } else if (!ptr[3]) { - /* .. at the end */ - ptr[1] = '\0'; - } - /* fallthrough */ - - default: - /* something else */ - ++ptr; - break; - } - } - } - - if (url->port) { - if ( ((url->port == 80) && !strcmp(url->scheme, "http")) - || ((url->port ==443) && !strcmp(url->scheme, "https")) -#ifdef HAVE_GETSERVBYNAME - || ((se = getservbyname(url->scheme, "tcp")) && se->s_port && - (url->port == ntohs(se->s_port))) -#endif - ) { - url->port = 0; - } - } - - if (url_str) { - size_t len; - - *url_str = emalloc(HTTP_URL_MAXLEN + 1); - - **url_str = '\0'; - strlcat(*url_str, url->scheme, HTTP_URL_MAXLEN); - strlcat(*url_str, "://", HTTP_URL_MAXLEN); - - if (url->user && *url->user) { - strlcat(*url_str, url->user, HTTP_URL_MAXLEN); - if (url->pass && *url->pass) { - strlcat(*url_str, ":", HTTP_URL_MAXLEN); - strlcat(*url_str, url->pass, HTTP_URL_MAXLEN); - } - strlcat(*url_str, "@", HTTP_URL_MAXLEN); - } - - strlcat(*url_str, url->host, HTTP_URL_MAXLEN); - - if (url->port) { - char port_str[8]; - - snprintf(port_str, sizeof(port_str), "%d", (int) url->port); - strlcat(*url_str, ":", HTTP_URL_MAXLEN); - strlcat(*url_str, port_str, HTTP_URL_MAXLEN); - } - - strlcat(*url_str, url->path, HTTP_URL_MAXLEN); - - if (url->query && *url->query) { - strlcat(*url_str, "?", HTTP_URL_MAXLEN); - strlcat(*url_str, url->query, HTTP_URL_MAXLEN); - } - - if (url->fragment && *url->fragment) { - strlcat(*url_str, "#", HTTP_URL_MAXLEN); - strlcat(*url_str, url->fragment, HTTP_URL_MAXLEN); - } - - if (HTTP_URL_MAXLEN == (len = strlen(*url_str))) { - http_error(HE_NOTICE, HTTP_E_URL, "Length of URL exceeds HTTP_URL_MAXLEN"); - } - if (url_len) { - *url_len = len; - } - } - - if (url_ptr) { - *url_ptr = url; - } else { - php_url_free(url); - } -} -/* }}} */ - -/* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */ -PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep, - char *pre_encoded_data, size_t pre_encoded_len, - char **encoded_data, size_t *encoded_len TSRMLS_DC) -{ - char *arg_sep; - size_t arg_sep_len; - phpstr *qstr = phpstr_new(); - - if (override_argsep || !(arg_sep_len = strlen(arg_sep = INI_STR("arg_separator.output")))) { - arg_sep = HTTP_URL_ARGSEP; - arg_sep_len = lenof(HTTP_URL_ARGSEP); - } - - if (pre_encoded_len && pre_encoded_data) { - phpstr_append(qstr, pre_encoded_data, pre_encoded_len); - } - - if (SUCCESS != http_urlencode_hash_recursive(hash, qstr, arg_sep, arg_sep_len, NULL, 0)) { - phpstr_free(&qstr); - return FAILURE; - } - - phpstr_data(qstr, encoded_data, encoded_len); - phpstr_free(&qstr); - - return SUCCESS; -} -/* }}} */ - -/* {{{ http_urlencode_hash_recursive */ -PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC) -{ - HashKey key = initHashKey(0); - zval **data = NULL; - HashPosition pos; - - if (!ht || !str) { - http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid parameters"); - return FAILURE; - } - if (ht->nApplyCount > 0) { - return SUCCESS; - } - - FOREACH_HASH_KEYVAL(pos, ht, key, data) { - char *encoded_key; - int encoded_len; - phpstr new_prefix; - - if (!data || !*data) { - phpstr_dtor(str); - return FAILURE; - } - - if (key.type == HASH_KEY_IS_STRING) { - if (!*key.str) { - /* only public properties */ - continue; - } - if (key.len && key.str[key.len - 1] == '\0') { - --key.len; - } - encoded_key = php_url_encode(key.str, key.len, &encoded_len); - } else { - encoded_len = spprintf(&encoded_key, 0, "%ld", key.num); - } - - { - phpstr_init(&new_prefix); - if (prefix && prefix_len) { - phpstr_append(&new_prefix, prefix, prefix_len); - phpstr_appends(&new_prefix, "%5B"); - } - - phpstr_append(&new_prefix, encoded_key, encoded_len); - efree(encoded_key); - - if (prefix && prefix_len) { - phpstr_appends(&new_prefix, "%5D"); - } - phpstr_fix(&new_prefix); - } - - if (Z_TYPE_PP(data) == IS_ARRAY || Z_TYPE_PP(data) == IS_OBJECT) { - STATUS status; - ++ht->nApplyCount; - status = http_urlencode_hash_recursive(HASH_OF(*data), str, arg_sep, arg_sep_len, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix)); - --ht->nApplyCount; - if (SUCCESS != status) { - phpstr_dtor(&new_prefix); - phpstr_dtor(str); - return FAILURE; - } - } else { - zval *val = http_zsep(IS_STRING, *data); - - if (PHPSTR_LEN(str)) { - phpstr_append(str, arg_sep, arg_sep_len); - } - phpstr_append(str, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix)); - phpstr_appends(str, "="); - - if (Z_STRLEN_P(val) && Z_STRVAL_P(val)) { - char *encoded_val; - int encoded_len; - - encoded_val = php_url_encode(Z_STRVAL_P(val), Z_STRLEN_P(val), &encoded_len); - phpstr_append(str, encoded_val, encoded_len); - efree(encoded_val); - } - - zval_ptr_dtor(&val); - } - phpstr_dtor(&new_prefix); - } - return SUCCESS; -} -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/http_util_object.c b/http_util_object.c deleted file mode 100644 index 9d984e6..0000000 --- a/http_util_object.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#include "php_http.h" - -#ifdef ZEND_ENGINE_2 - -#include "ext/standard/php_http.h" - -#include "php_http_util_object.h" - -#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpUtil, method, 0, req_args) -#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpUtil, method, 0) - -#define HTTP_UTIL_ALIAS(method, func) HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpUtil, method)) - -HTTP_BEGIN_ARGS(date, 0) - HTTP_ARG_VAL(timestamp, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(buildStr, 1) - HTTP_ARG_VAL(query, 0) - HTTP_ARG_VAL(prefix, 0) - HTTP_ARG_VAL(arg_sep, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(buildUrl, 1) - HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(parts, 0) - HTTP_ARG_VAL(flags, 0) - HTTP_ARG_VAL(composed, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(negotiateLanguage, 1) - HTTP_ARG_VAL(supported, 0) - HTTP_ARG_VAL(result, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(negotiateCharset, 1) - HTTP_ARG_VAL(supported, 0) - HTTP_ARG_VAL(result, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(negotiateContentType, 1) - HTTP_ARG_VAL(supported, 0) - HTTP_ARG_VAL(result, 1) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(matchModified, 1) - HTTP_ARG_VAL(last_modified, 0) - HTTP_ARG_VAL(for_range, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(matchEtag, 1) - HTTP_ARG_VAL(plain_etag, 0) - HTTP_ARG_VAL(for_range, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(matchRequestHeader, 2) - HTTP_ARG_VAL(header_name, 0) - HTTP_ARG_VAL(header_value, 0) - HTTP_ARG_VAL(case_sensitive, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(parseMessage, 1) - HTTP_ARG_VAL(message_string, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(parseHeaders, 1) - HTTP_ARG_VAL(headers_string, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(parseCookie, 1) - HTTP_ARG_VAL(cookie_string, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(buildCookie, 1) - HTTP_ARG_VAL(cookie_array, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(parseParams, 1) - HTTP_ARG_VAL(param_string, 0) - HTTP_ARG_VAL(flags, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(chunkedDecode, 1) - HTTP_ARG_VAL(encoded_string, 0) -HTTP_END_ARGS; - -#ifdef HTTP_HAVE_ZLIB -HTTP_BEGIN_ARGS(deflate, 1) - HTTP_ARG_VAL(plain, 0) - HTTP_ARG_VAL(flags, 0) -HTTP_END_ARGS; - -HTTP_BEGIN_ARGS(inflate, 1) - HTTP_ARG_VAL(encoded, 0) -HTTP_END_ARGS; -#endif - -HTTP_BEGIN_ARGS(support, 0) - HTTP_ARG_VAL(feature, 0) -HTTP_END_ARGS; - -zend_class_entry *http_util_object_ce; -zend_function_entry http_util_object_fe[] = { - HTTP_UTIL_ALIAS(date, http_date) - HTTP_UTIL_ALIAS(buildUrl, http_build_url) - HTTP_UTIL_ALIAS(buildStr, http_build_str) - HTTP_UTIL_ALIAS(negotiateLanguage, http_negotiate_language) - HTTP_UTIL_ALIAS(negotiateCharset, http_negotiate_charset) - HTTP_UTIL_ALIAS(negotiateContentType, http_negotiate_content_type) - HTTP_UTIL_ALIAS(matchModified, http_match_modified) - HTTP_UTIL_ALIAS(matchEtag, http_match_etag) - HTTP_UTIL_ALIAS(matchRequestHeader, http_match_request_header) - HTTP_UTIL_ALIAS(parseMessage, http_parse_message) - HTTP_UTIL_ALIAS(parseHeaders, http_parse_headers) - HTTP_UTIL_ALIAS(parseCookie, http_parse_cookie) - HTTP_UTIL_ALIAS(buildCookie, http_build_cookie) - HTTP_UTIL_ALIAS(parseParams, http_parse_params) - HTTP_UTIL_ALIAS(chunkedDecode, http_chunked_decode) -#ifdef HTTP_HAVE_ZLIB - HTTP_UTIL_ALIAS(deflate, http_deflate) - HTTP_UTIL_ALIAS(inflate, http_inflate) -#endif /* HTTP_HAVE_ZLIB */ - HTTP_UTIL_ALIAS(support, http_support) - - EMPTY_FUNCTION_ENTRY -}; - -PHP_MINIT_FUNCTION(http_util_object) -{ - HTTP_REGISTER_CLASS(HttpUtil, http_util_object, NULL, 0); - return SUCCESS; -} - -#endif /* ZEND_ENGINE_2 */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/lib/BigGet.php b/lib/BigGet.php deleted file mode 100644 index 73049a6..0000000 --- a/lib/BigGet.php +++ /dev/null @@ -1,213 +0,0 @@ - - * @license BSD, revised - * @version $Revision$ - */ -class BigGet extends HttpRequestPool -{ - /** - * File split size - */ - const SIZE = 1048576; - - /** - * Parallel Request count - */ - const RMAX = 5; - - /** - * Whether to output debug messages - * - * @var bool - */ - public $dbg = false; - - /** - * URL - * - * @var string - */ - private $url; - - /** - * Temp file prefix - * - * @var string - */ - private $tmp; - - /** - * Size of requested resource - * - * @var int - */ - private $size; - - /** - * Whether the requests have been sent - * - * @var bool - */ - private $sent = false; - - /** - * Request counter - * - * @var int - */ - private $count = 0; - - /** - * Static constructor - * - * @param string $url - * @param string $tmp - * @return BigGet - * @throws Exception - */ - public static function url($url, $tmp = '/tmp') - { - $head = new HttpRequest($url, HttpRequest::METH_HEAD); - $headers = $head->send()->getHeaders(); - - if (200 != $head->getResponseCode()) { - throw new HttpException("Did not receive '200 Ok' from HEAD $url"); - } - if (!isset($headers['Accept-Ranges'])) { - throw new HttpException("Did not receive an Accept-Ranges header from HEAD $url"); - } - if (!isset($headers['Content-Length'])) { - throw new HttpException("Did not receive a Content-Length header from HEAD $url"); - } - - $bigget = new BigGet; - $bigget->url = $url; - $bigget->tmp = tempnam($tmp, 'BigGet.'); - $bigget->size = $headers['Content-Length']; - return $bigget; - } - - /** - * Save the resource to a file - * - * @param string $file - * @return bool - * @throws Exception - */ - public function saveTo($file) - { - $this->sent or $this->send(); - - if ($w = fopen($this->tmp, 'wb')) { - - $this->dbg && print "\nCopying temp files to $file ...\n"; - - foreach (glob($this->tmp .".????") as $tmp) { - - $this->dbg && print "\t$tmp\n"; - - if ($r = fopen($tmp, 'rb')) { - stream_copy_to_stream($r, $w); - fclose($r); - } - unlink($tmp); - } - fclose($w); - rename($this->tmp, $file); - - $this->dbg && print "\nDone.\n"; - - return true; - } - return false; - } - - /** - * Overrides HttpRequestPool::send() - * - * @return void - * @throws Exception - */ - public function send() - { - $this->sent = true; - - // use max RMAX simultanous requests with a req size of SIZE - while ($this->count < self::RMAX && -1 != $offset = $this->getRangeOffset()) { - $this->attachNew($offset); - } - - while ($this->socketPerform()) { - if (!$this->socketSelect()) { - throw new HttpSocketException; - } - } - } - - /** - * Overrides HttpRequestPool::socketPerform() - * - * @return bool - */ - protected function socketPerform() - { - $rs = parent::socketPerform(); - - foreach ($this->getFinishedRequests() as $r) { - $this->detach($r); - - if (206 != $rc = $r->getResponseCode()) { - throw new HttpException("Unexpected response code: $rc"); - } - - file_put_contents(sprintf("%s.%04d", $this->tmp, $r->id), $r->getResponseBody()); - - if (-1 != $offset = $this->getRangeOffset()) { - $this->attachNew($offset); - } - } - - return $rs; - } - - private function attachNew($offset) - { - $stop = min($this->count * self::SIZE + self::SIZE, $this->size) - 1; - - $this->dbg && print "Attaching new request to get range: $offset-$stop\n"; - - $req = new BigGetRequest( - $this->url, - HttpRequest::METH_GET, - array( - 'headers' => array( - 'Range' => "bytes=$offset-$stop" - ) - ) - ); - $this->attach($req); - $req->id = $this->count++; - } - - private function getRangeOffset() - { - return ($this->size >= $start = $this->count * self::SIZE) ? $start : -1; - } -} - - -/** - * BigGet request - * @ignore - */ -class BigGetRequest extends HttpRequest -{ - public $id; -} - -?> diff --git a/lib/FeedAggregator.php b/lib/FeedAggregator.php deleted file mode 100644 index 689e788..0000000 --- a/lib/FeedAggregator.php +++ /dev/null @@ -1,187 +0,0 @@ - - * @license BSD, revised - * @package pecl/http - * @version $Revision$ - */ -class FeedAggregator -{ - /** - * Cache directory - * - * @var string - */ - public $directory; - - /** - * Feeds - * - * @var array - */ - protected $feeds = array(); - - /** - * Constructor - * - * @param string $directory - */ - public function __construct($directory = 'feeds') - { - $this->setDirectory($directory); - } - - /** - * Set cache directory - * - * @param string $directory - */ - public function setDirectory($directory) - { - $this->directory = $directory; - foreach (glob($this->directory .'/*.xml') as $feed) { - $this->feeds[basename($feed, '.xml')] = filemtime($feed); - } - } - - /** - * Strips all special chars - * - * @param string $url - * @return string - */ - public function url2name($url) - { - return preg_replace('/[^\w\.-]+/', '_', $url); - } - - /** - * Checks if $url is a known feed - * - * @param string $url - * @return bool - */ - public function hasFeed($url) - { - return isset($this->feeds[$this->url2name($url)]); - } - - /** - * Add an URL as feed - * - * @param string $url - * @return void - * @throws Exception - */ - public function addFeed($url) - { - $r = $this->setupRequest($url); - $r->send(); - $this->handleResponse($r); - } - - /** - * Add several URLs as feeds - * - * @param array $urls - * @return void - * @throws Exception - */ - public function addFeeds(array $urls) - { - $pool = new HttpRequestPool; - foreach ($urls as $url) { - $pool->attach($r = $this->setupRequest($url)); - } - $pool->send(); - - foreach ($pool as $request) { - $this->handleResponse($request); - } - } - - /** - * Load a feed (from cache) - * - * @param string $url - * @return string - * @throws Exception - */ - public function getFeed($url) - { - $this->addFeed($url); - return $this->loadFeed($this->url2name($url)); - } - - /** - * Load several feeds (from cache) - * - * @param array $urls - * @return array - * @throws Exception - */ - public function getFeeds(array $urls) - { - $feeds = array(); - $this->addFeeds($urls); - foreach ($urls as $url) { - $feeds[] = $this->loadFeed($this->url2name($url)); - } - return $feeds; - } - - protected function saveFeed($file, $contents) - { - if (file_put_contents($this->directory .'/'. $file .'.xml', $contents)) { - $this->feeds[$file] = time(); - } else { - throw new Exception("Could not save feed contents to $file.xml"); - } - } - - protected function loadFeed($file) - { - if (isset($this->feeds[$file])) { - if ($data = file_get_contents($this->directory .'/'. $file .'.xml')) { - return $data; - } else { - throw new Exception("Could not load feed contents from $file.xml"); - } - } else { - throw new Exception("Unknown feed/file $file.xml"); - } - } - - protected function setupRequest($url, $escape = true) - { - $r = new HttpRequest($url); - $r->setOptions(array('redirect' => true)); - - $file = $escape ? $this->url2name($url) : $url; - - if (isset($this->feeds[$file])) { - $r->setOptions(array('lastmodified' => $this->feeds[$file])); - } - - return $r; - } - - protected function handleResponse(HttpRequest $r) - { - if ($r->getResponseCode() != 304) { - if ($r->getResponseCode() != 200) { - throw new Exception("Unexpected response code ". $r->getResponseCode()); - } - if (!strlen($body = $r->getResponseBody())) { - throw new Exception("Received empty feed from ". $r->getUrl()); - } - $this->saveFeed($this->url2name($r->getUrl()), $body); - } - } -} - -?> diff --git a/lib/PgLobStream.php b/lib/PgLobStream.php deleted file mode 100644 index d050613..0000000 --- a/lib/PgLobStream.php +++ /dev/null @@ -1,100 +0,0 @@ - - * // GET /image.php?image=1234 - * if (PgLobStream::$loId = (int) $_GET['image']) { - * if ($lob = fopen('pglob://dbname=database user=mike', 'r')) { - * HttpResponse::setContentType('image/jpeg'); - * HttpResponse::setStream($lob); - * HttpResponse::send(); - * } - * } - * - * - * @copyright Michael Wallner, - * @license BSD, revised - * @package pecl/http - * @version $Revision$ - */ -class PgLobStream -{ - private $dbh; - private $loh; - private $lon; - private $size = 0; - - public static $loId; - - function stream_open($path, $mode) - { - $path = trim(parse_url($path, PHP_URL_HOST)); - - if ($path) { - if ($this->dbh = pg_connect($path)) { - if (pg_query($this->dbh, 'BEGIN')) { - if (is_resource($this->loh = pg_lo_open($this->dbh, $this->lon = self::$loId, $mode))) { - pg_lo_seek($this->loh, 0, PGSQL_SEEK_END); - $this->size = (int) pg_lo_tell($this->loh); - pg_lo_seek($this->loh, 0, PGSQL_SEEK_SET); - return true; - } - } - } - } - return false; - } - - function stream_read($length) - { - return pg_lo_read($this->loh, $length); - } - - function stream_seek($offset, $whence = PGSQL_SEEK_SET) - { - return pg_lo_seek($this->loh, $offset, $whence); - } - - function stream_tell() - { - return pg_lo_tell($this->loh); - } - - function stream_eof() - { - return pg_lo_tell($this->loh) >= $this->size; - } - - function stream_flush() - { - return true; - } - - function stream_stat() - { - return array('size' => $this->size, 'ino' => $this->lon); - } - - function stream_write($data) - { - return pg_lo_write($this->loh, $data); - } - - function stream_close() - { - if (pg_lo_close($this->loh)) { - return pg_query($this->dbh, 'COMMIT'); - } else { - pg_query($this->dbh, 'ROLLBACK'); - return false; - } - } -} - -stream_register_wrapper('pglob', 'PgLobStream'); - -?> diff --git a/lib/XmlRpcClient.php b/lib/XmlRpcClient.php deleted file mode 100644 index 8668291..0000000 --- a/lib/XmlRpcClient.php +++ /dev/null @@ -1,119 +0,0 @@ - - * __request->setOptions(array('compress' => true)); - * try { - * print_r($rpc->vpop->listdomain(array('domain' => 'example.com'))); - * } catch (Exception $ex) { - * echo $ex; - * } - * ?> - * - * - * @copyright Michael Wallner, - * @license BSD, revised - * @package pecl/http - * @version $Revision$ - */ -class XmlRpcClient -{ - /** - * RPC namespace - * - * @var string - */ - public $__namespace; - - /** - * HttpRequest instance - * - * @var HttpRequest - */ - public $__request; - - /** - * Client charset - * - * @var string - */ - public $__encoding = "iso-8859-1"; - - /** - * RPC options - * - * @var array - */ - public $__options; - - /** - * Constructor - * - * @param string $url RPC endpoint - * @param string $namespace RPC namespace - * @param array $options HttpRequest options - */ - public function __construct($url, $namespace = '', array $options = null) - { - $this->__request = new HttpRequest($url, HttpRequest::METH_POST, (array) $options); - $this->__namespace = $namespace; - } - - /** - * RPC method proxy - * - * @param string $method RPC method name - * @param array $params RPC method arguments - * @return mixed decoded RPC response - * @throws Exception - */ - public function __call($method, array $params) - { - if (strlen($this->__namespace)) { - $method = $this->__namespace .'.'. $method; - } - $this->__request->setContentType("text/xml"); - $this->__request->setRawPostData( - xmlrpc_encode_request($method, $params, - array("encoding" => $this->__encoding) + (array) $this->__options)); - $response = $this->__request->send(); - if ($response->getResponseCode() != 200) { - throw new Exception( - $response->getResponseStatus(), - $response->getResponseCode() - ); - } - - $data = xmlrpc_decode($response->getBody(), $this->__encoding); - if (xmlrpc_is_fault($data)) { - throw new Exception( - (string) $data['faultString'], - (int) $data['faultCode'] - ); - } - - return $data; - } - - /** - * Returns self, where namespace is set to variable name - * - * @param string $ns - * @return XmlRpcRequest - */ - public function __get($ns) - { - $this->__namespace = $ns; - return $this; - } -} - -?> diff --git a/lib/XmlRpcServer.php b/lib/XmlRpcServer.php deleted file mode 100644 index c8c1ac4..0000000 --- a/lib/XmlRpcServer.php +++ /dev/null @@ -1,254 +0,0 @@ - - * registerHandler(new Handler); - * XmlRpcServer::run(); - * } catch (Exception $ex) { - * XmlRpcServer::error($ex->getCode(), $ex->getMessage()); - * } - * - * - * @copyright Michael Wallner, - * @license BSD, revised - * @package pecl/http - * @version $Revision$ - */ - -class XmlRpcServer extends HttpResponse -{ - /** - * Server charset - * - * @var string - */ - public static $encoding = "iso-8859-1"; - - /** - * RPC namespace - * - * @var string - */ - public $namespace; - - /** - * RPC handler attached to this server instance - * - * @var XmlRpcRequestHandler - */ - protected $handler; - - private static $xmlreq; - private static $xmlrpc; - private static $refcnt = 0; - private static $handle = array(); - - /** - * Create a new XmlRpcServer instance - * - * @param string $namespace - * @param string $encoding - */ - public function __construct($namespace) - { - $this->namespace = $namespace; - self::initialize(); - } - - /** - * Destructor - */ - public function __destruct() - { - if (self::$refcnt && !--self::$refcnt) { - xmlrpc_server_destroy(self::$xmlrpc); - } - } - - /** - * Static factory - * - * @param string $namespace - * @return XmlRpcServer - */ - public static function factory($namespace) - { - return new XmlRpcServer($namespace); - } - - /** - * Run all servers and send response - * - * @param array $options - */ - public static function run(array $options = null) - { - self::initialize(false, true); - self::setContentType("text/xml; charset=". self::$encoding); - echo xmlrpc_server_call_method(self::$xmlrpc, self::$xmlreq, null, - array("encoding" => self::$encoding) + (array) $options); - } - - /** - * Test hook; call instead of XmlRpcServer::run() - * - * @param string $method - * @param array $params - * @param array $request_options - * @param array $response_options - */ - public static function test($method, array $params, array $request_options = null, array $response_options = null) - { - self::$xmlreq = xmlrpc_encode_request($method, $params, $request_options); - self::run($response_options); - } - - /** - * Optional XMLRPC error handler - * - * @param int $code - * @param string $msg - */ - public static function error($code, $msg, array $options = null) - { - echo xmlrpc_encode(array("faultCode" => $code, "faultString" => $msg), - array("encoding" => self::$encoding) + (array) $options); - } - - /** - * Register a single method - * - * @param string $name - * @param mixed $callback - * @param mixed $dispatch - * @param array $spec - */ - public function registerMethod($name, $callback, $dispatch = null, array $spec = null) - { - if (!is_callable($callback, false, $cb_name)) { - throw new Exception("$cb_name is not a valid callback"); - } - if (isset($dispatch)) { - if (!is_callable($dispatch, false, $cb_name)) { - throw new Exception("$cb_name is not a valid callback"); - } - xmlrpc_server_register_method(self::$xmlrpc, $name, $dispatch); - self::$handle[$name] = $callback; - } else { - xmlrpc_server_register_method(self::$xmlrpc, $name, $callback); - } - - if (isset($spec)) { - xmlrpc_server_add_introspection_data(self::$xmlrpc, $spec); - } - } - - /** - * Register an XmlRpcRequestHandler for this server instance - * - * @param XmlRpcRequestHandler $handler - */ - public function registerHandler(XmlRpcRequestHandler $handler) - { - $this->handler = $handler; - - foreach (get_class_methods($handler) as $method) { - if (!strncmp($method, "xmlrpc", 6)) { - $this->registerMethod( - $this->method($method, $handler->getNamespace()), - array($handler, $method), array($this, "dispatch")); - } - } - - $handler->getIntrospectionData($spec); - if (is_array($spec)) { - xmlrpc_server_add_introspection_data(self::$xmlrpc, $spec); - } - } - - private function method($method, $namespace = null) - { - if (!strlen($namespace)) { - $namespace = strlen($this->namespace) ? $this->namespace : "xmlrpc"; - } - return $namespace .".". strtolower($method[6]) . substr($method, 7); - } - - private function dispatch($method, array $params = null) - { - if (array_key_exists($method, self::$handle)) { - return call_user_func(self::$handle[$method], $params); - } - throw new Exception("Unknown XMLRPC method: $method"); - } - - private static function initialize($server = true, $data = false) - { - if ($data) { - if (!self::$xmlreq && !(self::$xmlreq = http_get_request_body())) { - throw new Exception("Failed to fetch XMLRPC request body"); - } - } - if ($server) { - if (!self::$xmlrpc && !(self::$xmlrpc = xmlrpc_server_create())) { - throw new Exception("Failed to initialize XMLRPC server"); - } - ++self::$refcnt; - } - } -} - -/** - * XmlRpcRequestHandler - * - * Define XMLRPC methods with an "xmlrpc" prefix, eg: - * - * class IntOp implements XmlRpcRequestHandler { - * public function getNamespace() { - * return "int"; - * } - * public function getInstrospectionData(array &$spec = null) { - * } - * // XMLRPC method name: int.sumValues - * public function xmlrpcSumValues(array $values) { - * return array_sum($values); - * } - * } - *
- */ -interface XmlRpcRequestHandler -{ - public function getNamespace(); - public function getIntrospectionData(array &$spec = null); -} - -/** - * XmlRpcRequestHandlerStub - */ -abstract class XmlRpcRequestHandlerStub implements XmlRpcRequestHandler -{ - public function getNamespace() - { - } - public function getIntrospectionData(array &$spec = null) - { - } -} - -?> diff --git a/missing.c b/missing.c deleted file mode 100644 index 65851be..0000000 --- a/missing.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner| - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "php.h" -#include "missing.h" - -#ifdef WONKY -int zend_declare_property_double(zend_class_entry *ce, char *name, int name_length, double value, int access_type TSRMLS_DC) -{ - zval *property = pemalloc(sizeof(zval), ce->type & ZEND_INTERNAL_CLASS); - INIT_PZVAL(property); - ZVAL_DOUBLE(property, value); - return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC); -} - -void zend_update_property_double(zend_class_entry *scope, zval *object, char *name, int name_length, double value TSRMLS_DC) -{ - zval *tmp = ecalloc(1, sizeof(zval)); - ZVAL_DOUBLE(tmp, value); - zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC); -} - -int zend_declare_property_bool(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC) -{ - zval *property = pemalloc(sizeof(zval), ce->type & ZEND_INTERNAL_CLASS); - INIT_PZVAL(property); - ZVAL_BOOL(property, value); - return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC); -} - -void zend_update_property_bool(zend_class_entry *scope, zval *object, char *name, int name_length, long value TSRMLS_DC) -{ - zval *tmp = ecalloc(1, sizeof(zval)); - ZVAL_BOOL(tmp, value); - zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC); -} - -void zend_update_property_stringl(zend_class_entry *scope, zval *object, char *name, int name_length, char *value, int value_len TSRMLS_DC) -{ - zval *tmp; - - ALLOC_ZVAL(tmp); - tmp->is_ref = 0; - tmp->refcount = 0; - ZVAL_STRINGL(tmp, value, value_len, 1); - zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC); -} - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/missing.h b/missing.h deleted file mode 100644 index 3efe1a2..0000000 --- a/missing.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_MISSING -#define PHP_HTTP_MISSING - -#include "php_version.h" - -#if ZEND_MODULE_API_NO >= 20100409 -#define ZEND_ENGINE_2_4 -#endif - -#if defined(PHP_VERSION_ID) && (PHP_VERSION_ID >= 50500) -# define ZEND_GET_PPTR_TYPE_DC , int type -# define ZEND_GET_PPTR_TYPE_CC , type -#else -# define ZEND_GET_PPTR_TYPE_DC -# define ZEND_GET_PPTR_TYPE_CC -#endif - -#if defined(PHP_VERSION_ID) && (PHP_VERSION_ID >= 50399) -# define ZEND_LITERAL_KEY_DC , const zend_literal *_zend_literal_key -# define ZEND_LITERAL_KEY_CC , _zend_literal_key -# define ZEND_LITERAL_NIL_CC , NULL -# define HTTP_CHECK_OPEN_BASEDIR(file, act) \ - if ((PG(open_basedir) && *PG(open_basedir))) \ - { \ - const char *tmp = file; \ - \ - if (!strncasecmp(tmp, "file:", lenof("file:"))) { \ - tmp += lenof("file:"); \ - while ((tmp - (const char *)file < 7) && (*tmp == '/' || *tmp == '\\')) ++tmp; \ - } \ - \ - if ( (tmp != file || !strstr(file, "://")) && \ - (!*tmp || php_check_open_basedir(tmp TSRMLS_CC))) { \ - act; \ - } \ - } - -#else -# define ZEND_LITERAL_KEY_DC -# define ZEND_LITERAL_KEY_CC -# define ZEND_LITERAL_NIL_CC -# define HTTP_CHECK_OPEN_BASEDIR(file, act) \ - if ((PG(open_basedir) && *PG(open_basedir)) || PG(safe_mode)) \ - { \ - const char *tmp = file; \ - \ - if (!strncasecmp(tmp, "file:", lenof("file:"))) { \ - tmp += lenof("file:"); \ - while ((tmp - (const char *)file < 7) && (*tmp == '/' || *tmp == '\\')) ++tmp; \ - } \ - \ - if ( (tmp != file || !strstr(file, "://")) && \ - (!*tmp || php_check_open_basedir(tmp TSRMLS_CC) || \ - (PG(safe_mode) && !php_checkuid(tmp, "rb+", CHECKUID_CHECK_MODE_PARAM)))) { \ - act; \ - } \ - } - -#endif - -#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3) -# define HTTP_ZAPI_HASH_TSRMLS_CC TSRMLS_CC -# define HTTP_ZAPI_HASH_TSRMLS_DC TSRMLS_DC -# define HTTP_ZAPI_CONST_CAST(t) (const t) -# define GLOBAL_ERROR_HANDLING EG(error_handling) -# define GLOBAL_EXCEPTION_CLASS EG(exception_class) -# define HTTP_IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp) TSRMLS_CC) -# define HTTP_STATIC_ARG_INFO -#else -# define HTTP_ZAPI_HASH_TSRMLS_CC -# define HTTP_ZAPI_HASH_TSRMLS_DC -# define HTTP_ZAPI_CONST_CAST(t) (t) -# define GLOBAL_ERROR_HANDLING PG(error_handling) -# define GLOBAL_EXCEPTION_CLASS PG(exception_class) -# define HTTP_IS_CALLABLE(cb_zv, flags, cb_sp) zend_is_callable((cb_zv), (flags), (cb_sp)) -# define HTTP_STATIC_ARG_INFO static -#endif - -#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION == 0) -# define WONKY -#endif - -#ifndef pemalloc_rel -# define pemalloc_rel(size, persistent) ((persistent)?malloc(size):emalloc_rel(size)) -#endif - -#ifndef ZEND_ACC_DEPRECATED -# define ZEND_ACC_DEPRECATED 0 -#endif - -#if PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION == 3 && PHP_RELEASE_VERSION < 10 -# define php_url_parse_ex(u, l) php_url_parse(u) -#endif - -#ifndef TSRMLS_FETCH_FROM_CTX -# ifdef ZTS -# define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = (void ***) ctx -# else -# define TSRMLS_FETCH_FROM_CTX(ctx) -# endif -#endif - -#ifndef TSRMLS_SET_CTX -# ifdef ZTS -# define TSRMLS_SET_CTX(ctx) ctx = (void ***) tsrm_ls -# else -# define TSRMLS_SET_CTX(ctx) -# endif -#endif - -#ifndef ZVAL_ADDREF -# define ZVAL_ADDREF Z_ADDREF_P -#endif - -#ifndef SEPARATE_ARG_IF_REF -#define SEPARATE_ARG_IF_REF(zv) \ - if (PZVAL_IS_REF(zv)) { \ - zval *ov = zv; \ - ALLOC_INIT_ZVAL(zv); \ - Z_TYPE_P(zv) = Z_TYPE_P(ov); \ - zv->value = ov->value; \ - zval_copy_ctor(zv); \ - } else { \ - ZVAL_ADDREF(zv); \ - } -#endif - -#ifndef ZVAL_ZVAL -#define ZVAL_ZVAL(z, zv, copy, dtor) { \ - int is_ref, refcount; \ - is_ref = (z)->is_ref; \ - refcount = (z)->refcount; \ - *(z) = *(zv); \ - if (copy) { \ - zval_copy_ctor(z); \ - } \ - if (dtor) { \ - if (!copy) { \ - ZVAL_NULL(zv); \ - } \ - zval_ptr_dtor(&zv); \ - } \ - (z)->is_ref = is_ref; \ - (z)->refcount = refcount; \ - } -#endif -#ifndef RETVAL_ZVAL -# define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor) -#endif -#ifndef RETURN_ZVAL -# define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; } -#endif - -#ifndef ZEND_MN -# define ZEND_MN(name) ZEND_FN(name) -#endif - -#ifdef WONKY -extern int zend_declare_property_double(zend_class_entry *ce, char *name, int name_length, double value, int access_type TSRMLS_DC); -extern void zend_update_property_double(zend_class_entry *scope, zval *object, char *name, int name_length, double value TSRMLS_DC); - -extern int zend_declare_property_bool(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC); -extern void zend_update_property_bool(zend_class_entry *scope, zval *object, char *name, int name_length, long value TSRMLS_DC); - -extern void zend_update_property_stringl(zend_class_entry *scope, zval *object, char *name, int name_length, char *value, int value_len TSRMLS_DC); -#endif - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/package.xml b/package.xml index cdbfe09..5467a83 100644 --- a/package.xml +++ b/package.xml @@ -14,8 +14,8 @@ This HTTP extension aims to provide a convenient and powerful set of functionality for one of PHPs major applications. -It eases handling of HTTP urls, dates, redirects, headers and -messages, provides means for negotiation of clients preferred +It eases handling of HTTP urls, headers and messages, provides +means for negotiation of a client's preferred content type, language and charset, as well as a convenient way to send any arbitrary data with caching and resuming capabilities. @@ -28,18 +28,25 @@ support. Parallel requests are available for PHP 5 and greater. mike@php.net yes -2013-06-20 +2013-08-12 - 1.7.6 -1.7.0 +2.0.0RC1 +2.0.0 - stable -stable +beta +beta BSD, revised @@ -47,227 +54,203 @@ support. Parallel requests are available for PHP 5 and greater. - - - - - - - - - - -- - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 4.3 +5.3.0 + 1.4.1 + +raphf +pecl.php.net +0.1.0 +raphf ++ propro +pecl.php.net +0.1.0 +propro +- @@ -275,33 +258,25 @@ support. Parallel requests are available for PHP 5 and greater.- spl session hash iconv http + name="with-http" + prompt="Enable extended HTTP support" + default="yes" /> + name="with-http-zlib-dir" + prompt="where to find zlib" + default="/usr" /> + name="with-http-libcurl-dir" + prompt="where to find libcurl" + default="/usr" /> + name="with-http-libevent-dir" + prompt="where to find libevent" + default="/usr" /> - + diff --git a/php_http.c b/php_http.c new file mode 100644 index 0000000..2ed94c8 --- /dev/null +++ b/php_http.c @@ -0,0 +1,261 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#include +#include + +#include + +#if PHP_HTTP_HAVE_CURL +# include +# if PHP_HTTP_HAVE_EVENT +# include +# endif +#endif +#if PHP_HTTP_HAVE_SERF +# include +#endif + +ZEND_DECLARE_MODULE_GLOBALS(php_http); + +#ifdef COMPILE_DL_HTTP +ZEND_GET_MODULE(http) +#endif + +zend_function_entry http_functions[] = { + EMPTY_FUNCTION_ENTRY +}; + +PHP_MINIT_FUNCTION(http); +PHP_MSHUTDOWN_FUNCTION(http); +PHP_RINIT_FUNCTION(http); +PHP_RSHUTDOWN_FUNCTION(http); +PHP_MINFO_FUNCTION(http); + +static zend_module_dep http_module_deps[] = { + ZEND_MOD_REQUIRED("raphf") + ZEND_MOD_REQUIRED("propro") + ZEND_MOD_REQUIRED("spl") +#ifdef PHP_HTTP_HAVE_HASH + ZEND_MOD_REQUIRED("hash") +#endif +#ifdef PHP_HTTP_HAVE_ICONV + ZEND_MOD_REQUIRED("iconv") +#endif +#ifdef PHP_HTTP_HAVE_JSON + ZEND_MOD_REQUIRED("json") +#endif +#ifdef PHP_HTTP_HAVE_EVENT + ZEND_MOD_CONFLICTS("event") +#endif + {NULL, NULL, NULL, 0} +}; + +zend_module_entry http_module_entry = { + STANDARD_MODULE_HEADER_EX, + NULL, + http_module_deps, + "http", + http_functions, + PHP_MINIT(http), + PHP_MSHUTDOWN(http), + PHP_RINIT(http), + PHP_RSHUTDOWN(http), + PHP_MINFO(http), + PHP_HTTP_EXT_VERSION, + STANDARD_MODULE_PROPERTIES +}; + +int http_module_number; + +#if PHP_DEBUG && !HAVE_GCOV +void _dpf(int type, const char *data, size_t length) +{ + static const char _sym[] = "><><><"; + if (type) { + int nwp = 0; + for (fprintf(stderr, "%c ", _sym[type-1]); length--; data++) { + int ip = PHP_HTTP_IS_CTYPE(print, *data); + if (!ip && *data != '\r' && *data != '\n') nwp = 1; + fprintf(stderr, ip?"%c":"\\x%02x", (int) (*data & 0xff)); + if (!nwp && *data == '\n' && length) { + fprintf(stderr, "\n%c ", _sym[type-1]); + } + } + fprintf(stderr, "\n"); + } else { + fprintf(stderr, "# %.*s\n", (int) length, data); + } +} +#endif + +static void php_http_globals_init_once(zend_php_http_globals *G) +{ + memset(G, 0, sizeof(*G)); +} + +#if 0 +static inline void php_http_globals_init(zend_php_http_globals *G TSRMLS_DC) +{ +} + +static inline void php_http_globals_free(zend_php_http_globals *G TSRMLS_DC) +{ +} +#endif + +#if ZTS && PHP_DEBUG && !HAVE_GCOV +zend_php_http_globals *php_http_globals(void) +{ + TSRMLS_FETCH(); + return PHP_HTTP_G; +} +#endif + +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("http.etag.mode", "crc32b", PHP_INI_ALL, OnUpdateString, env.etag_mode, zend_php_http_globals, php_http_globals) +PHP_INI_END() + +PHP_MINIT_FUNCTION(http) +{ + http_module_number = module_number; + ZEND_INIT_MODULE_GLOBALS(php_http, php_http_globals_init_once, NULL); + REGISTER_INI_ENTRIES(); + + if (0 + || SUCCESS != PHP_MINIT_CALL(http_exception) + || SUCCESS != PHP_MINIT_CALL(http_cookie) + || SUCCESS != PHP_MINIT_CALL(http_encoding) + || SUCCESS != PHP_MINIT_CALL(http_filter) + || SUCCESS != PHP_MINIT_CALL(http_header) + || SUCCESS != PHP_MINIT_CALL(http_message) + || SUCCESS != PHP_MINIT_CALL(http_message_body) + || SUCCESS != PHP_MINIT_CALL(http_querystring) + || SUCCESS != PHP_MINIT_CALL(http_client) + || SUCCESS != PHP_MINIT_CALL(http_client_request) + || SUCCESS != PHP_MINIT_CALL(http_client_response) +#if PHP_HTTP_HAVE_CURL + || SUCCESS != PHP_MINIT_CALL(http_curl) + || SUCCESS != PHP_MINIT_CALL(http_client_curl) +#endif + || SUCCESS != PHP_MINIT_CALL(http_url) + || SUCCESS != PHP_MINIT_CALL(http_env) + || SUCCESS != PHP_MINIT_CALL(http_env_request) + || SUCCESS != PHP_MINIT_CALL(http_env_response) + || SUCCESS != PHP_MINIT_CALL(http_params) + ) { + return FAILURE; + } + + return SUCCESS; +} + + + +PHP_MSHUTDOWN_FUNCTION(http) +{ + UNREGISTER_INI_ENTRIES(); + + if (0 + || SUCCESS != PHP_MSHUTDOWN_CALL(http_message) +#if PHP_HTTP_HAVE_CURL + || SUCCESS != PHP_MSHUTDOWN_CALL(http_client_curl) + || SUCCESS != PHP_MSHUTDOWN_CALL(http_curl) +#endif + || SUCCESS != PHP_MSHUTDOWN_CALL(http_client) + ) { + return FAILURE; + } + + return SUCCESS; +} + +PHP_RINIT_FUNCTION(http) +{ + if (0 + || SUCCESS != PHP_RINIT_CALL(http_env) +#if PHP_HTTP_HAVE_CURL && PHP_HTTP_HAVE_EVENT + || SUCCESS != PHP_RINIT_CALL(http_client_curl) +#endif + ) { + return FAILURE; + } + + return SUCCESS; +} + +PHP_RSHUTDOWN_FUNCTION(http) +{ + if (0 +#if PHP_HTTP_HAVE_CURL && PHP_HTTP_HAVE_EVENT + || SUCCESS != PHP_RSHUTDOWN_CALL(http_client_curl) +#endif + || SUCCESS != PHP_RSHUTDOWN_CALL(http_env) + ) { + return FAILURE; + } + + return SUCCESS; +} + +PHP_MINFO_FUNCTION(http) +{ + php_http_buffer_t buf; + + php_http_buffer_init(&buf); + + php_info_print_table_start(); + php_info_print_table_header(2, "HTTP Support", "enabled"); + php_info_print_table_row(2, "Extension Version", PHP_HTTP_EXT_VERSION); + php_info_print_table_end(); + + php_info_print_table_start(); + php_info_print_table_header(3, "Used Library", "Compiled", "Linked"); + php_info_print_table_row(3, "libz", ZLIB_VERSION, zlibVersion()); +#if PHP_HTTP_HAVE_CURL + { + curl_version_info_data *cv = curl_version_info(CURLVERSION_NOW); + php_info_print_table_row(3, "libcurl", LIBCURL_VERSION, cv->version); + } +#else + php_info_print_table_row(3, "libcurl", "disabled", "disabled"); +#endif + +#if PHP_HTTP_HAVE_EVENT + php_info_print_table_row(3, "libevent", +# ifdef LIBEVENT_VERSION + LIBEVENT_VERSION, +# else + PHP_HTTP_EVENT_VERSION, +# endif + event_get_version()); +#else + php_info_print_table_row(3, "libevent", "disabled", "disabled"); +#endif + + php_info_print_table_end(); + + DISPLAY_INI_ENTRIES(); +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http.h b/php_http.h index e4a0f85..8e341ca 100644 --- a/php_http.h +++ b/php_http.h @@ -6,250 +6,21 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | + | Copyright (c) 2004-2013, Michael Wallner | +--------------------------------------------------------------------+ */ -/* $Id$ */ - #ifndef PHP_EXT_HTTP_H #define PHP_EXT_HTTP_H -#define PHP_HTTP_VERSION "1.7.6" - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# ifndef PHP_WIN32 -# include "php_config.h" -# endif -#endif - -#include "php.h" -#include "missing.h" -#include "php_http_std_defs.h" -#include "phpstr/phpstr.h" - -#ifdef HTTP_WANT_SAPI -# if PHP_API_VERSION > 20041225 -# define HTTP_HAVE_SAPI_RTIME -# endif -# include "SAPI.h" -#endif - -#ifdef HTTP_WANT_NETDB -# ifdef PHP_WIN32 -# define HTTP_HAVE_NETDB -# include -# elif defined(HAVE_NETDB_H) -# define HTTP_HAVE_NETDB -# include -# ifdef HAVE_UNISTD_H -# include -# endif -# endif -#endif - -#if defined(HTTP_WANT_CURL) && defined(HTTP_HAVE_CURL) -# ifdef PHP_WIN32 -# include -# define CURL_STATICLIB -# endif -# include -# define HTTP_CURL_VERSION(x, y, z) (LIBCURL_VERSION_NUM >= (((x)<<16) + ((y)<<8) + (z))) -# -# if defined(HTTP_WANT_EVENT) && defined(HTTP_HAVE_EVENT) -# include -# endif -#endif - -#if defined(HTTP_WANT_MAGIC) && defined(HTTP_HAVE_MAGIC) -# if defined(PHP_WIN32) && !defined(USE_MAGIC_DLL) && !defined(USE_MAGIC_STATIC) -# define USE_MAGIC_STATIC -# endif -# include -#endif - -#if defined(HTTP_WANT_ZLIB) && defined(HTTP_HAVE_ZLIB) -# include -#endif - -#include -#define HTTP_IS_CTYPE(type, c) is##type((int) (unsigned char) (c)) -#define HTTP_TO_CTYPE(type, c) to##type((int) (unsigned char) (c)) +#define PHP_HTTP_EXT_VERSION "2.0.0dev" extern zend_module_entry http_module_entry; #define phpext_http_ptr &http_module_entry extern int http_module_number; -ZEND_BEGIN_MODULE_GLOBALS(http) - - struct _http_globals_etag { - char *mode; - void *ctx; - zend_bool started; - } etag; - - struct _http_globals_log { - char *cache; - char *redirect; - char *not_found; - char *allowed_methods; - char *composite; - } log; - - struct _http_globals_send { - double throttle_delay; - size_t buffer_size; - char *content_type; - char *unquoted_etag; - time_t last_modified; - struct _http_globals_send_deflate { - zend_bool response; - zend_bool start_auto; - long start_flags; - int encoding; - void *stream; - } deflate; - struct _http_globals_send_inflate { - zend_bool start_auto; - long start_flags; - void *stream; - } inflate; - zend_bool not_found_404; - } send; - - struct _http_globals_request { - time_t time; - HashTable *headers; - struct _http_globals_request_methods { - HashTable registered; - char *allowed; - char *custom; - } methods; -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) - struct _http_globals_request_datashare { - zend_llist handles; - zend_bool cookie; - zend_bool dns; - zend_bool ssl; - zend_bool connect; - } datashare; -#endif -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_EVENT) - struct _http_globals_request_pool { - struct _http_globals_request_pool_event { - void *base; - } event; - } pool; -#endif - } request; - - struct _http_globals_persistent { - struct _http_globals_persistent_handles { - ulong limit; - struct _http_globals_persistent_handles_ident { - ulong h; - char *s; - size_t l; - } ident; - } handles; - } persistent; - -#ifdef ZEND_ENGINE_2 - zend_bool only_exceptions; -#endif - - zend_bool force_exit; - zend_bool read_post_data; - zval *server_var; - -ZEND_END_MODULE_GLOBALS(http) - -ZEND_EXTERN_MODULE_GLOBALS(http); - -#ifdef ZTS -# include "TSRM.h" -# define HTTP_G ((zend_http_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(http_globals_id)]) -#else -# define HTTP_G (&http_globals) -#endif - -#if defined(HAVE_ICONV) && (HTTP_SHARED_DEPS || !defined(COMPILE_DL_ICONV)) -# define HTTP_HAVE_ICONV -#endif - -#if defined(HAVE_PHP_SESSION) && (HTTP_SHARED_DEPS || !defined(COMPILE_DL_SESSION)) -# define HTTP_HAVE_SESSION -#endif - -#if defined(HAVE_HASH_EXT) && (HTTP_SHARED_DEPS || !defined(COMPILE_DL_HASH)) && defined(HTTP_HAVE_PHP_HASH_H) -# define HTTP_HAVE_HASH -#endif - -#if defined(HAVE_SPL) -# define HTTP_HAVE_SPL -#endif - -PHP_FUNCTION(http_date); -PHP_FUNCTION(http_build_url); -PHP_FUNCTION(http_build_str); -PHP_FUNCTION(http_negotiate_language); -PHP_FUNCTION(http_negotiate_charset); -PHP_FUNCTION(http_negotiate_content_type); -PHP_FUNCTION(http_negotiate); -PHP_FUNCTION(http_redirect); -PHP_FUNCTION(http_throttle); -PHP_FUNCTION(http_send_status); -PHP_FUNCTION(http_send_last_modified); -PHP_FUNCTION(http_send_content_type); -PHP_FUNCTION(http_send_content_disposition); -PHP_FUNCTION(http_match_modified); -PHP_FUNCTION(http_match_etag); -PHP_FUNCTION(http_cache_last_modified); -PHP_FUNCTION(http_cache_etag); -PHP_FUNCTION(http_send_data); -PHP_FUNCTION(http_send_file); -PHP_FUNCTION(http_send_stream); -PHP_FUNCTION(http_chunked_decode); -PHP_FUNCTION(http_parse_message); -PHP_FUNCTION(http_parse_headers); -PHP_FUNCTION(http_parse_cookie); -PHP_FUNCTION(http_build_cookie); -PHP_FUNCTION(http_parse_params); -PHP_FUNCTION(http_get_request_headers); -PHP_FUNCTION(http_get_request_body); -PHP_FUNCTION(http_get_request_body_stream); -PHP_FUNCTION(http_match_request_header); -PHP_FUNCTION(http_persistent_handles_count); -PHP_FUNCTION(http_persistent_handles_clean); -PHP_FUNCTION(http_persistent_handles_ident); -#ifdef HTTP_HAVE_CURL -PHP_FUNCTION(http_get); -PHP_FUNCTION(http_head); -PHP_FUNCTION(http_post_data); -PHP_FUNCTION(http_post_fields); -PHP_FUNCTION(http_put_data); -PHP_FUNCTION(http_put_file); -PHP_FUNCTION(http_put_stream); -PHP_FUNCTION(http_request); -PHP_FUNCTION(http_request_body_encode); -#endif /* HTTP_HAVE_CURL */ -PHP_FUNCTION(http_request_method_register); -PHP_FUNCTION(http_request_method_unregister); -PHP_FUNCTION(http_request_method_exists); -PHP_FUNCTION(http_request_method_name); -PHP_FUNCTION(ob_etaghandler); -#ifdef HTTP_HAVE_ZLIB -PHP_FUNCTION(http_deflate); -PHP_FUNCTION(http_inflate); -PHP_FUNCTION(ob_deflatehandler); -PHP_FUNCTION(ob_inflatehandler); -#endif -PHP_FUNCTION(http_support); - -#endif /* PHP_HTTP_H */ +#endif /* PHP_EXT_HTTP_H */ /* * Local variables: diff --git a/php_http_api.h b/php_http_api.h index 3a64350..42d34fc 100644 --- a/php_http_api.h +++ b/php_http_api.h @@ -6,314 +6,138 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | + | Copyright (c) 2004-2013, Michael Wallner | +--------------------------------------------------------------------+ */ -/* $Id$ */ - #ifndef PHP_HTTP_API_H #define PHP_HTTP_API_H -#define HTTP_SUPPORT 0x01L -#define HTTP_SUPPORT_REQUESTS 0x02L -#define HTTP_SUPPORT_MAGICMIME 0x04L -#define HTTP_SUPPORT_ENCODINGS 0x08L -#define HTTP_SUPPORT_SSLREQUESTS 0x20L -#define HTTP_SUPPORT_PERSISTENCE 0x40L -#define HTTP_SUPPORT_EVENTS 0x80L - -#define HTTP_PARAMS_ALLOW_COMMA 0x01 -#define HTTP_PARAMS_ALLOW_FAILURE 0x02 -#define HTTP_PARAMS_RAISE_ERROR 0x04 -#define HTTP_PARAMS_DEFAULT (HTTP_PARAMS_ALLOW_COMMA|HTTP_PARAMS_ALLOW_FAILURE|HTTP_PARAMS_RAISE_ERROR) -#define HTTP_PARAMS_COLON_SEPARATOR 0x10 - -extern PHP_MINIT_FUNCTION(http_support); - -#define http_support(f) _http_support(f) -PHP_HTTP_API long _http_support(long feature); - -#define pretty_key(key, key_len, uctitle, xhyphen) _http_pretty_key(key, key_len, uctitle, xhyphen) -extern char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen); - -#define http_boundary(b, l) _http_boundary((b), (l) TSRMLS_CC) -extern size_t _http_boundary(char *buf, size_t len TSRMLS_DC); - -#define http_error(type, code, string) _http_error_ex(type, code, "%s", string) -#define http_error_ex _http_error_ex -extern void _http_error_ex(long type TSRMLS_DC, long code, const char *format, ...); - - -#ifdef ZEND_ENGINE_2 -#define http_exception_wrap(o, n, ce) _http_exception_wrap((o), (n), (ce) TSRMLS_CC) -extern zval *_http_exception_wrap(zval *old_exception, zval *new_exception, zend_class_entry *ce TSRMLS_DC); +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -#define http_try \ -{ \ - zval *old_exception = EG(exception); \ - EG(exception) = NULL; -#define http_catch(ex_ce) \ - if (EG(exception) && old_exception) { \ - EG(exception) = http_exception_wrap(old_exception, EG(exception), ex_ce); \ - } \ -} -#define http_final(ex_ce) \ - if (EG(exception)) { \ - EG(exception) = http_exception_wrap(EG(exception), NULL, ex_ce); \ - } +#ifndef PHP_WIN32 +#include +#endif +#include +#include -typedef zend_object_value (*http_object_new_t)(zend_class_entry *ce, void *, void ** TSRMLS_DC); +#include +#include +#include +#include +#include -#define http_object_new(ov, cn, cl, co, ce, i, pp) _http_object_new((ov), (cn), (cl), (http_object_new_t) (co), (ce), (i), (void *) (pp) TSRMLS_CC) -extern STATUS _http_object_new(zend_object_value *ov, const char *cname_str, uint cname_len, http_object_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC); -#endif /* ZEND_ENGINE_2 */ +#include +#include -#define HTTP_CHECK_CURL_INIT(ch, init, action) \ - if ((!(ch)) && (!((ch) = init))) { \ - http_error(HE_WARNING, HTTP_E_REQUEST, "Could not initialize curl"); \ - action; \ - } -#define HTTP_CHECK_CONTENT_TYPE(ct, action) \ - if (!strchr((ct), '/')) { \ - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, \ - "Content type \"%s\" does not seem to contain a primary and a secondary part", (ct)); \ - action; \ - } -#define HTTP_CHECK_MESSAGE_TYPE_RESPONSE(msg, action) \ - if (!HTTP_MSG_TYPE(RESPONSE, (msg))) { \ - http_error(HE_NOTICE, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_RESPONSE"); \ - action; \ - } -#define HTTP_CHECK_MESSAGE_TYPE_REQUEST(msg, action) \ - if (!HTTP_MSG_TYPE(REQUEST, (msg))) { \ - http_error(HE_NOTICE, HTTP_E_MESSAGE_TYPE, "HttpMessage is not of type HTTP_MSG_REQUEST"); \ - action; \ - } -#define HTTP_CHECK_GZIP_LEVEL(level, action) \ - if (level < -1 || level > 9) { \ - http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid compression level (-1 to 9): %d", level); \ - action; \ - } -#ifndef PHP_OUTPUT_NEWAPI -# define HTTP_GET_OUTPUT_START() \ - char *output_start_filename = php_get_output_start_filename(TSRMLS_C); \ - int output_start_lineno = php_get_output_start_lineno(TSRMLS_C) +#ifdef PHP_WIN32 +# define PHP_HTTP_API __declspec(dllexport) +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define PHP_HTTP_API extern __attribute__ ((visibility("default"))) #else -# define HTTP_GET_OUTPUT_START() \ - char *output_start_filename = php_output_get_start_filename(TSRMLS_C); \ - int output_start_lineno = php_output_get_start_lineno(TSRMLS_C) +# define PHP_HTTP_API extern #endif -#define HTTP_CHECK_HEADERS_SENT(action) \ - if (SG(headers_sent) && !SG(request_info).no_headers) { \ - HTTP_GET_OUTPUT_START(); \ - if (output_start_filename) { \ - http_error_ex(HE_WARNING, HTTP_E_HEADER, "Cannot modify header information - headers already sent by (output started at %s:%d)", \ - output_start_filename, output_start_lineno); \ - } else { \ - http_error(HE_WARNING, HTTP_E_HEADER, "Cannot modify header information - headers already sent"); \ - } \ - action; \ - } - -#define http_log(f, i, m) _http_log_ex((f), (i), (m) TSRMLS_CC) -extern void _http_log_ex(char *file, const char *ident, const char *message TSRMLS_DC); - -#define http_exit(s, h) http_exit_ex((s), (h), NULL, 1) -#define http_exit_ex(s, h, b, e) _http_exit_ex((s), (h), (b), (e) TSRMLS_CC) -extern STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC); - -#define http_check_method(m) http_check_method_ex((m), HTTP_KNOWN_METHODS) -#define http_check_method_ex(m, a) _http_check_method_ex((m), (a)) -extern STATUS _http_check_method_ex(const char *method, const char *methods); - -#define http_got_server_var(v) (NULL != http_get_server_var_ex((v), strlen(v), 1)) -#define http_get_server_var(v, c) http_get_server_var_ex((v), strlen(v), (c)) -#define http_get_server_var_ex(v, l, c) _http_get_server_var_ex((v), (l), (c) TSRMLS_CC) -PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_len, zend_bool check TSRMLS_DC); - -#define http_get_request_body(b, l) _http_get_request_body_ex((b), (l), 1 TSRMLS_CC) -#define http_get_request_body_ex(b, l, d) _http_get_request_body_ex((b), (l), (d) TSRMLS_CC) -PHP_HTTP_API STATUS _http_get_request_body_ex(char **body, size_t *length, zend_bool dup TSRMLS_DC); - -#define http_get_request_body_stream() _http_get_request_body_stream(TSRMLS_C) -PHP_HTTP_API php_stream *_http_get_request_body_stream(TSRMLS_D); - -typedef void (*http_parse_params_callback)(void *cb_arg, const char *key, int keylen, const char *val, int vallen TSRMLS_DC); +/* make functions that return SUCCESS|FAILURE more obvious */ +typedef int STATUS; -#define http_parse_params_default_callback _http_parse_params_default_callback -PHP_HTTP_API void _http_parse_params_default_callback(void *ht, const char *key, int keylen, const char *val, int vallen TSRMLS_DC); +#if (defined(HAVE_ICONV) || defined(PHP_HTTP_HAVE_EXT_ICONV)) && (PHP_HTTP_SHARED_DEPS || !defined(COMPILE_DL_ICONV)) +# define PHP_HTTP_HAVE_ICONV +#endif -#define http_parse_params(s, f, ht) _http_parse_params_ex((s), (f), _http_parse_params_default_callback, (ht) TSRMLS_CC) -#define http_parse_params_ex(s, f, cb, a) _http_parse_params_ex((s), (f), (cb), (a) TSRMLS_CC) -PHP_HTTP_API STATUS _http_parse_params_ex(const char *params, int flags, http_parse_params_callback cb, void *cb_arg TSRMLS_DC); +#if (defined(HAVE_HASH_EXT) || defined(PHP_HTTP_HAVE_EXT_HASH)) && (PHP_HTTP_SHARED_DEPS || !defined(COMPILE_DL_HASH)) && defined(PHP_HTTP_HAVE_PHP_HASH_H) +# define PHP_HTTP_HAVE_HASH +#endif +#if (defined(HAVE_JSON) || defined(PHP_HTTP_HAVE_EXT_JSON)) && (PHP_HTTP_SHARED_DEPS || !defined(COMPILE_DL_JSON)) +# define PHP_HTTP_HAVE_JSON +#endif -#define http_sleep(s) _http_sleep(s) -static inline void _http_sleep(double s) -{ -#define HTTP_DIFFSEC (0.001) -#define HTTP_MLLISEC (1000) -#define HTTP_MCROSEC (1000 * 1000) -#define HTTP_NANOSEC (1000 * 1000 * 1000) -#define HTTP_MSEC(s) ((long)(s * HTTP_MLLISEC)) -#define HTTP_USEC(s) ((long)(s * HTTP_MCROSEC)) -#define HTTP_NSEC(s) ((long)(s * HTTP_NANOSEC)) +#ifdef PHP_WIN32 +# define CURL_STATICLIB +# define PHP_HTTP_HAVE_NETDB +# include +#elif defined(HAVE_NETDB_H) +# define PHP_HTTP_HAVE_NETDB +# include +# ifdef HAVE_UNISTD_H +# include +# endif +# ifdef HAVE_ERRNO_H +# include +# endif +#endif -#if defined(PHP_WIN32) - Sleep((DWORD) HTTP_MSEC(s)); -#elif defined(HAVE_USLEEP) - usleep(HTTP_USEC(s)); -#elif defined(HAVE_NANOSLEEP) - struct timespec req, rem; +#include +#define PHP_HTTP_IS_CTYPE(type, c) is##type((int) (unsigned char) (c)) +#define PHP_HTTP_TO_CTYPE(type, c) to##type((int) (unsigned char) (c)) + +#include "php_http.h" + +#include "php_http_buffer.h" +#include "php_http_strlist.h" +#include "php_http_misc.h" +#include "php_http_options.h" + +#include "php_http.h" +#include "php_http_cookie.h" +#include "php_http_encoding.h" +#include "php_http_info.h" +#include "php_http_message.h" +#include "php_http_env.h" +#include "php_http_env_request.h" +#include "php_http_env_response.h" +#include "php_http_etag.h" +#include "php_http_exception.h" +#include "php_http_filter.h" +#include "php_http_header_parser.h" +#include "php_http_header.h" +#include "php_http_message_body.h" +#include "php_http_message_parser.h" +#include "php_http_negotiate.h" +#include "php_http_object.h" +#include "php_http_params.h" +#include "php_http_querystring.h" +#include "php_http_client.h" +#include "php_http_curl.h" +#include "php_http_client_request.h" +#include "php_http_client_response.h" +#include "php_http_client_curl.h" +#include "php_http_url.h" +#include "php_http_version.h" + +ZEND_BEGIN_MODULE_GLOBALS(php_http) + struct php_http_env_globals env; +#if PHP_HTTP_HAVE_CURL && PHP_HTTP_HAVE_EVENT + struct php_http_curl_globals curl; +#endif +ZEND_END_MODULE_GLOBALS(php_http) - req.tv_sec = (time_t) s; - req.tv_nsec = HTTP_NSEC(s) % HTTP_NANOSEC; +ZEND_EXTERN_MODULE_GLOBALS(php_http); - while (nanosleep(&req, &rem) && (errno == EINTR) && (HTTP_NSEC(rem.tv_sec) + rem.tv_nsec) > HTTP_NSEC(HTTP_DIFFSEC))) { - req.tv_sec = rem.tv_sec; - req.tv_nsec = rem.tv_nsec; - } +#ifdef ZTS +# include "TSRM/TSRM.h" +# define PHP_HTTP_G ((zend_php_http_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(php_http_globals_id)]) +# undef TSRMLS_FETCH_FROM_CTX +# define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = ((ctx)?(ctx):ts_resource_ex(0, NULL)) #else - struct timeval timeout; - - timeout.tv.sec = (time_t) s; - timeout.tv_usec = HTTP_USEC(s) % HTTP_MCROSEC; - - select(0, NULL, NULL, NULL, &timeout); +# define PHP_HTTP_G (&php_http_globals) #endif -} - -#define http_locate_str _http_locate_str -static inline const char *_http_locate_str(const char *h, size_t h_len, const char *n, size_t n_len) -{ - const char *p, *e; - - if (n_len && h_len) { - e = h + h_len; - do { - if (*h == *n) { - for (p = n; *p == h[p-n]; ++p) { - if (p == n+n_len-1) { - return h; - } - } - } - } while (h++ != e); - } - - return NULL; -} - -#define http_locate_body _http_locate_body -static inline const char *_http_locate_body(const char *message) -{ - const char *body = NULL, *msg = message; - - while (*msg) { - if (*msg == '\n') { - if (*(msg+1) == '\n') { - body = msg + 2; - break; - } else if (*(msg+1) == '\r' && *(msg+2) == '\n') { - body = msg + 3; - break; - } - } - ++msg; - } - return body; -} - -#define http_locate_eol _http_locate_eol -static inline const char *_http_locate_eol(const char *line, int *eol_len) -{ - const char *eol = strpbrk(line, "\r\n"); - - if (eol_len) { - *eol_len = eol ? ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1) : 0; - } - return eol; -} - -#define http_zset(t, z) _http_zset((t), (z)) -static inline zval *_http_zset(int type, zval *z) -{ - if (Z_TYPE_P(z) != type) { - switch (type) { - case IS_NULL: convert_to_null(z); break; - case IS_BOOL: convert_to_boolean(z); break; - case IS_LONG: convert_to_long(z); break; - case IS_DOUBLE: convert_to_double(z); break; - case IS_STRING: convert_to_string(z); break; - case IS_ARRAY: convert_to_array(z); break; - case IS_OBJECT: convert_to_object(z); break; - } - } - return z; -} -#define http_zsep(t, z) _http_zsep_ex((t), (z), NULL) -#define http_zsep_ex(t, z, p) _http_zsep_ex((t), (z), (p)) -static inline zval *_http_zsep_ex(int type, zval *z, zval **p) { - ZVAL_ADDREF(z); - if (Z_TYPE_P(z) != type) { - switch (type) { - case IS_NULL: convert_to_null_ex(&z); break; - case IS_BOOL: convert_to_boolean_ex(&z); break; - case IS_LONG: convert_to_long_ex(&z); break; - case IS_DOUBLE: convert_to_double_ex(&z); break; - case IS_STRING: convert_to_string_ex(&z); break; - case IS_ARRAY: convert_to_array_ex(&z); break; - case IS_OBJECT: convert_to_object_ex(&z); break; - } - } else { - SEPARATE_ZVAL_IF_NOT_REF(&z); - } - if (p) { - *p = z; - } - return z; -} -typedef struct _HashKey { - char *str; - uint len; - ulong num; - uint dup:1; - uint type:31; -} HashKey; -#define initHashKey(dup) {NULL, 0, 0, (dup), 0} - -#define FOREACH_VAL(pos, array, val) FOREACH_HASH_VAL(pos, Z_ARRVAL_P(array), val) -#define FOREACH_HASH_VAL(pos, hash, val) \ - for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ - zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \ - zend_hash_move_forward_ex(hash, &pos)) - -#define FOREACH_KEY(pos, array, key) FOREACH_HASH_KEY(pos, Z_ARRVAL_P(array), key) -#define FOREACH_HASH_KEY(pos, hash, _key) \ - for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ - ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (zend_bool) (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT; \ - zend_hash_move_forward_ex(hash, &pos)) \ - -#define FOREACH_KEYVAL(pos, array, key, val) FOREACH_HASH_KEYVAL(pos, Z_ARRVAL_P(array), key, val) -#define FOREACH_HASH_KEYVAL(pos, hash, _key, val) \ - for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ - ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (zend_bool) (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT && \ - zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \ - zend_hash_move_forward_ex(hash, &pos)) - -#define array_copy(src, dst) zend_hash_copy(dst, src, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)) -#define ARRAY_JOIN_STRONLY 1 -#define ARRAY_JOIN_PRETTIFY 2 -#define array_join(src, dst, append, flags) zend_hash_apply_with_arguments(src HTTP_ZAPI_HASH_TSRMLS_CC, (append)?apply_array_append_func:apply_array_merge_func, 2, dst, (int)flags) +#if PHP_DEBUG +# define _DPF_STR 0 +# define _DPF_IN 1 +# define _DPF_OUT 2 +extern void _dpf(int type, const char *data, size_t length); +#else +# define _dpf(t,s,l); +#endif -extern int apply_array_append_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key); -extern int apply_array_merge_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key); +#endif /* PHP_HTTP_API_H */ -#endif /* * Local variables: @@ -323,4 +147,3 @@ extern int apply_array_merge_func(void *pDest HTTP_ZAPI_HASH_TSRMLS_DC, int num_ * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ - diff --git a/php_http_buffer.c b/php_http_buffer.c new file mode 100644 index 0000000..84272d0 --- /dev/null +++ b/php_http_buffer.c @@ -0,0 +1,457 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include +#include "php_http_buffer.h" + +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_init_ex(php_http_buffer_t *buf, size_t chunk_size, int flags) +{ + if (!buf) { + buf = pemalloc(sizeof(*buf), flags & PHP_HTTP_BUFFER_INIT_PERSISTENT); + } + + if (buf) { + buf->size = (chunk_size) ? chunk_size : PHP_HTTP_BUFFER_DEFAULT_SIZE; + buf->pmem = (flags & PHP_HTTP_BUFFER_INIT_PERSISTENT) ? 1 : 0; + buf->data = (flags & PHP_HTTP_BUFFER_INIT_PREALLOC) ? pemalloc(buf->size, buf->pmem) : NULL; + buf->free = (flags & PHP_HTTP_BUFFER_INIT_PREALLOC) ? buf->size : 0; + buf->used = 0; + } + + return buf; +} + +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_from_string_ex(php_http_buffer_t *buf, const char *string, size_t length) +{ + if ((buf = php_http_buffer_init(buf))) { + if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(buf, string, length)) { + pefree(buf, buf->pmem); + buf = NULL; + } + } + return buf; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer_t *buf, size_t len, size_t override_size, int allow_error) +{ + char *ptr = NULL; +#if 0 + fprintf(stderr, "RESIZE: len=%lu, size=%lu, used=%lu, free=%lu\n", len, buf->size, buf->used, buf->free); +#endif + if (buf->free < len) { + size_t size = override_size ? override_size : buf->size; + + while ((size + buf->free) < len) { + size <<= 1; + } + + if (allow_error) { + ptr = perealloc_recoverable(buf->data, buf->used + buf->free + size, buf->pmem); + } else { + ptr = perealloc(buf->data, buf->used + buf->free + size, buf->pmem); + } + + if (ptr) { + buf->data = ptr; + } else { + return PHP_HTTP_BUFFER_NOMEM; + } + + buf->free += size; + return size; + } + return 0; +} + +PHP_HTTP_BUFFER_API char *php_http_buffer_account(php_http_buffer_t *buf, size_t to_account) +{ + /* it's probably already too late but check anyway */ + if (to_account > buf->free) { + return NULL; + } + + buf->free -= to_account; + buf->used += to_account; + + return buf->data + buf->used; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer_t *buf) +{ + /* avoid another realloc on fixation */ + if (buf->free > 1) { + char *ptr = perealloc(buf->data, buf->used + 1, buf->pmem); + + if (ptr) { + buf->data = ptr; + } else { + return PHP_HTTP_BUFFER_NOMEM; + } + buf->free = 1; + } + return buf->used; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer_t *buf, const char *append, size_t append_len) +{ + if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, append_len)) { + return PHP_HTTP_BUFFER_NOMEM; + } + memcpy(buf->data + buf->used, append, append_len); + buf->used += append_len; + buf->free -= append_len; + return append_len; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer_t *buf, const char *format, ...) +{ + va_list argv; + char *append; + size_t append_len, alloc; + + va_start(argv, format); + append_len = vspprintf(&append, 0, format, argv); + va_end(argv); + + alloc = php_http_buffer_append(buf, append, append_len); + efree(append); + + if (PHP_HTTP_BUFFER_NOMEM == alloc) { + return PHP_HTTP_BUFFER_NOMEM; + } + return append_len; +} + +PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer_t *buf, char **into, size_t *len) +{ + char *copy = ecalloc(1, buf->used + 1); + memcpy(copy, buf->data, buf->used); + if (into) { + *into = copy; + } + if (len) { + *len = buf->used; + } + return copy; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer_t *buf, size_t offset, size_t length) +{ + if (offset > buf->used) { + return 0; + } + if (offset + length > buf->used) { + length = buf->used - offset; + } + memmove(buf->data + offset, buf->data + offset + length, buf->used - length - offset); + buf->used -= length; + buf->free += length; + return length; +} + +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_fix(php_http_buffer_t *buf) +{ + if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(buf, 1, 1, 0)) { + return NULL; + } + buf->data[buf->used] = '\0'; + return buf; +} + +PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer_t *buf) +{ + buf->free += buf->used; + buf->used = 0; +} + +PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer_t *buf) +{ + if (buf->data) { + pefree(buf->data, buf->pmem); + buf->data = NULL; + } + buf->used = 0; + buf->free = 0; +} + +PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer_t **buf) +{ + if (*buf) { + php_http_buffer_dtor(*buf); + pefree(*buf, (*buf)->pmem); + *buf = NULL; + } +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer_t **s, const char *data, size_t data_len, char **chunk, size_t chunk_size) +{ + php_http_buffer_t *storage; + + *chunk = NULL; + + if (!*s) { + *s = php_http_buffer_init_ex(NULL, chunk_size << 1, chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0); + } + storage = *s; + + if (data_len) { + php_http_buffer_append(storage, data, data_len); + } + + if (!chunk_size) { + php_http_buffer_data(storage, chunk, &chunk_size); + php_http_buffer_free(s); + return chunk_size; + } + + if (storage->used >= chunk_size) { + *chunk = estrndup(storage->data, chunk_size); + php_http_buffer_cut(storage, 0, chunk_size); + return chunk_size; + } + + return 0; +} + +PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_len, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC) +{ + char *chunk = NULL; + size_t got = 0; + + while ((got = php_http_buffer_chunk_buffer(s, data, data_len, &chunk, chunk_len))) { + passout(opaque, chunk, got TSRMLS_CC); + if (!chunk_len) { + /* we already got the last chunk, + and freed all resources */ + break; + } + data = NULL; + data_len = 0; + STR_SET(chunk, NULL); + } + STR_FREE(chunk); +} + +PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg TSRMLS_DC) +{ + size_t passed_on = 0, passed_in = php_http_buffer_chunked_input(s, chunk_size, passin, passin_arg TSRMLS_CC); + + if (passed_in == PHP_HTTP_BUFFER_PASS0) { + return passed_in; + } + if (passed_in || (*s)->used) { + passed_on = passon(passon_arg, (*s)->data, (*s)->used TSRMLS_CC); + + if (passed_on == PHP_HTTP_BUFFER_PASS0) { + return passed_on; + } + + if (passed_on) { + php_http_buffer_cut(*s, 0, passed_on); + } + } + + return passed_on - passed_in; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque TSRMLS_DC) +{ + php_http_buffer_t *str; + size_t passed; + + if (!*s) { + *s = php_http_buffer_init_ex(NULL, chunk_size, chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0); + } + str = *s; + + php_http_buffer_resize(str, chunk_size); + passed = passin(opaque, str->data + str->used, chunk_size TSRMLS_CC); + + if (passed != PHP_HTTP_BUFFER_PASS0) { + str->used += passed; + str->free -= passed; + } + + php_http_buffer_fix(str); + + return passed; +} + +#ifdef PHP_HTTP_BUFFER_EXTENDED + +PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer_t *left, php_http_buffer_t *right) +{ + if (left->used > right->used) { + return -1; + } else if (right->used > left->used) { + return 1; + } else { + return memcmp(left->data, right->data, left->used); + } +} + +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_copy(const php_http_buffer_t *from, php_http_buffer_t *to) +{ + int free_to = !to; + + to = php_http_buffer_clone(from, to); + + if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(to, from->data, from->used)) { + if (free_to) { + php_http_buffer_free(&to); + } else { + php_http_buffer_dtor(to); + } + } + return to; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_insert(php_http_buffer_t *buf, const char *insert, size_t insert_len, size_t offset) +{ + if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, insert_len)) { + return PHP_HTTP_BUFFER_NOMEM; + } + memmove(buf->data + offset + insert_len, buf->data + offset, insert_len); + memcpy(buf->data + offset, insert, insert_len); + buf->used += insert_len; + buf->free -= insert_len; + return insert_len; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer_t *buf, size_t offset, const char *format, ...) +{ + va_list argv; + char *insert; + size_t insert_len, alloc; + + va_start(argv, format); + insert_len = vspprintf(&insert, 0, format, argv); + va_end(argv); + + alloc = php_http_buffer_insert(buf, insert, insert_len, offset); + efree(insert); + + if (PHP_HTTP_BUFFER_NOMEM == alloc) { + return PHP_HTTP_BUFFER_NOMEM; + } + return insert_len; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_prepend(php_http_buffer_t *buf, const char *prepend, size_t prepend_len) +{ + if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, prepend_len)) { + return PHP_HTTP_BUFFER_NOMEM; + } + memmove(buf->data + prepend_len, buf->data, buf->used); + memcpy(buf->data, prepend, prepend_len); + buf->used += prepend_len; + buf->free -= prepend_len; + return prepend_len; +} + +PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer_t *buf, const char *format, ...) +{ + va_list argv; + char *prepend; + size_t prepend_len, alloc; + + va_start(argv, format); + prepend_len = vspprintf(&prepend, 0, format, argv); + va_end(argv); + + alloc = php_http_buffer_prepend(buf, prepend, prepend_len); + efree(prepend); + + if (PHP_HTTP_BUFFER_NOMEM == alloc) { + return PHP_HTTP_BUFFER_NOMEM; + } + return prepend_len; +} + +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_sub(const php_http_buffer_t *buf, size_t offset, size_t length) +{ + if (offset >= buf->used) { + return NULL; + } else { + size_t need = 1 + ((length + offset) > buf->used ? (buf->used - offset) : (length - offset)); + php_http_buffer_t *sub = php_http_buffer_init_ex(NULL, need, PHP_HTTP_BUFFER_INIT_PREALLOC | (buf->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT:0)); + if (sub) { + if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(sub, buf->data + offset, need)) { + php_http_buffer_free(&sub); + } else { + sub->size = buf->size; + } + } + return sub; + } +} + +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_right(const php_http_buffer_t *buf, size_t length) +{ + if (length < buf->used) { + return php_http_buffer_sub(buf, buf->used - length, length); + } else { + return php_http_buffer_sub(buf, 0, buf->used); + } +} + + +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_va(php_http_buffer_t *buf, unsigned argc, va_list argv) +{ + unsigned i = 0; + buf = php_http_buffer_init(buf); + + if (buf) { + while (argc > i++) { + php_http_buffer_free_t f = va_arg(argv, php_http_buffer_free_t); + php_http_buffer_t *current = va_arg(argv, php_http_buffer_t *); + php_http_buffer_append(buf, current->data, current->used); + FREE_PHP_HTTP_BUFFER(f, current); + } + } + + return buf; +} + +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_ex(php_http_buffer_t *buf, unsigned argc, ...) +{ + va_list argv; + php_http_buffer_t *ret; + + va_start(argv, argc); + ret = php_http_buffer_merge_va(buf, argc, argv); + va_end(argv); + return ret; +} + +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge(unsigned argc, ...) +{ + va_list argv; + php_http_buffer_t *ret; + + va_start(argv, argc); + ret = php_http_buffer_merge_va(NULL, argc, argv); + va_end(argv); + return ret; +} + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ + diff --git a/php_http_buffer.h b/php_http_buffer.h new file mode 100644 index 0000000..8ee4eae --- /dev/null +++ b/php_http_buffer.h @@ -0,0 +1,250 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_BUFFER_H +#define PHP_HTTP_BUFFER_H + +#ifndef PHP_HTTP_BUFFER_DEFAULT_SIZE +# define PHP_HTTP_BUFFER_DEFAULT_SIZE 256 +#endif + +#define PHP_HTTP_BUFFER_ERROR ((size_t) -1) +#define PHP_HTTP_BUFFER_NOMEM PHP_HTTP_BUFFER_ERROR +#define PHP_HTTP_BUFFER_PASS0 PHP_HTTP_BUFFER_ERROR + +#ifndef STR_FREE +# define STR_FREE(STR) \ + { \ + if (STR) { \ + efree(STR); \ + } \ + } +#endif +#ifndef STR_SET +# define STR_SET(STR, SET) \ + { \ + STR_FREE(STR); \ + STR = SET; \ + } +#endif +#ifndef TSRMLS_D +# define TSRMLS_D +# define TSRMLS_DC +# define TSRMLS_CC +# define TSRMLS_C +#endif +#ifdef PHP_ATTRIBUTE_FORMAT +# define PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(f, a, b) PHP_ATTRIBUTE_FORMAT(f, a, b) +#else +# define PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(f, a, b) +#endif +#ifndef pemalloc +# define pemalloc(s,p) malloc(s) +# define pefree(x,p) free(x) +# define perealloc(x,s,p) realloc(x,s) +# define perealloc_recoverable perealloc +# define ecalloc calloc +static inline void *estrndup(void *p, size_t s) +{ + char *r = (char *) malloc(s+1); + if (r) memcpy((void *) r, p, s), r[s] = '\0'; + return (void *) r; +} +#endif + +#if defined(PHP_WIN32) +# if defined(PHP_HTTP_BUFFER_EXPORTS) +# define PHP_HTTP_BUFFER_API __declspec(dllexport) +# elif defined(COMPILE_DL_PHP_HTTP_BUFFER) +# define PHP_HTTP_BUFFER_API __declspec(dllimport) +# else +# define PHP_HTTP_BUFFER_API +# endif +#else +# define PHP_HTTP_BUFFER_API +#endif + +#define PHP_HTTP_BUFFER(p) ((php_http_buffer_t *) (p)) + +#define FREE_PHP_HTTP_BUFFER_PTR(STR) pefree(STR, STR->pmem) +#define FREE_PHP_HTTP_BUFFER_VAL(STR) php_http_buffer_dtor(STR) +#define FREE_PHP_HTTP_BUFFER_ALL(STR) php_http_buffer_free(&(STR)) +#define FREE_PHP_HTTP_BUFFER(free, STR) \ + switch (free) \ + { \ + case PHP_HTTP_BUFFER_FREE_NOT: \ + break; \ + case PHP_HTTP_BUFFER_FREE_PTR: \ + pefree(STR, STR->pmem); break; \ + break; \ + case PHP_HTTP_BUFFER_FREE_VAL: \ + php_http_buffer_dtor(STR); \ + break; \ + case PHP_HTTP_BUFFER_FREE_ALL: { \ + php_http_buffer_t *PTR = (STR); \ + php_http_buffer_free(&PTR); \ + break; \ + } \ + default:\ + break; \ + } + +#define RETURN_PHP_HTTP_BUFFER_PTR(STR) RETURN_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_PTR, 0) +#define RETURN_PHP_HTTP_BUFFER_VAL(STR) RETURN_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 0) +#define RETURN_PHP_HTTP_BUFFER_DUP(STR) RETURN_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 1) +#define RETVAL_PHP_HTTP_BUFFER_PTR(STR) RETVAL_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_PTR, 0) +#define RETVAL_PHP_HTTP_BUFFER_VAL(STR) RETVAL_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 0) +#define RETVAL_PHP_HTTP_BUFFER_DUP(STR) RETVAL_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 1) +/* RETURN_PHP_HTTP_BUFFER(buf, PHP_HTTP_BUFFER_FREE_PTR, 0) */ +#define RETURN_PHP_HTTP_BUFFER(STR, free, dup) \ + RETVAL_PHP_HTTP_BUFFER((STR), (free), (dup)); \ + return; + +#define RETVAL_PHP_HTTP_BUFFER(STR, free, dup) \ + php_http_buffer_fix(STR); \ + RETVAL_STRINGL((STR)->data, (STR)->used, (dup)); \ + FREE_PHP_HTTP_BUFFER((free), (STR)); + +typedef struct php_http_buffer { + char *data; + size_t used; + size_t free; + size_t size; + unsigned pmem:1; + unsigned reserved:31; +} php_http_buffer_t; + +typedef enum php_http_buffer_free { + PHP_HTTP_BUFFER_FREE_NOT = 0, + PHP_HTTP_BUFFER_FREE_PTR, /* pefree() */ + PHP_HTTP_BUFFER_FREE_VAL, /* php_http_buffer_dtor() */ + PHP_HTTP_BUFFER_FREE_ALL /* php_http_buffer_free() */ +} php_http_buffer_free_t; + +#define PHP_HTTP_BUFFER_ALL_FREE(STR) PHP_HTTP_BUFFER_FREE_ALL,(STR) +#define PHP_HTTP_BUFFER_PTR_FREE(STR) PHP_HTTP_BUFFER_FREE_PTR,(STR) +#define PHP_HTTP_BUFFER_VAL_FREE(STR) PHP_HTTP_BUFFER_FREE_VAL,(STR) +#define PHP_HTTP_BUFFER_NOT_FREE(STR) PHP_HTTP_BUFFER_FREE_NOT,(STR) + +#define PHP_HTTP_BUFFER_INIT_PREALLOC 0x01 +#define PHP_HTTP_BUFFER_INIT_PERSISTENT 0x02 + +/* create a new php_http_buffer_t */ +#define php_http_buffer_new() php_http_buffer_init(NULL) +#define php_http_buffer_init(b) php_http_buffer_init_ex(b, PHP_HTTP_BUFFER_DEFAULT_SIZE, 0) +#define php_http_buffer_clone(from, to) php_http_buffer_init_ex((to), (from)->size, (from)->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT:0) +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_init_ex(php_http_buffer_t *buf, size_t chunk_size, int flags); + +/* create a php_http_buffer_t from a zval or c-string */ +#define php_http_buffer_from_zval(z) php_http_buffer_from_string(Z_STRVAL(z), Z_STRLEN(z)) +#define php_http_buffer_from_zval_ex(b, z) php_http_buffer_from_string_ex(b, Z_STRVAL(z), Z_STRLEN(z)) +#define php_http_buffer_from_string(s, l) php_http_buffer_from_string_ex(NULL, (s), (l)) +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_from_string_ex(php_http_buffer_t *buf, const char *string, size_t length); + +/* usually only called from within the internal functions */ +#define php_http_buffer_resize(b, s) php_http_buffer_resize_ex((b), (s), 0, 0) +PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer_t *buf, size_t len, size_t override_size, int allow_error); + +PHP_HTTP_BUFFER_API char *php_http_buffer_account(php_http_buffer_t *buf, size_t to_account); + +/* shrink memory chunk to actually used size (+1) */ +PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer_t *buf); + +/* append data to the php_http_buffer_t */ +#define php_http_buffer_appends(b, a) php_http_buffer_append((b), (a), sizeof(a)-1) +#define php_http_buffer_appendl(b, a) php_http_buffer_append((b), (a), strlen(a)) +PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer_t *buf, const char *append, size_t append_len); +PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer_t *buf, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 2, 3); + +/* get a zero-terminated string */ +PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer_t *buf, char **into, size_t *len); + +/* remove a substring */ +PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer_t *buf, size_t offset, size_t length); + +/* sets a trailing NUL byte */ +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_fix(php_http_buffer_t *buf); + +/* reset php_http_buffer_t object */ +PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer_t *buf); + +/* free a php_http_buffer_t objects contents */ +PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer_t *buf); + +/* free a php_http_buffer_t object completely */ +PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer_t **buf); + +/* stores data in a php_http_buffer_t until it reaches chunk_size */ +PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer_t **s, const char *data, size_t data_len, char **chunk, size_t chunk_size); + +typedef size_t (*php_http_buffer_pass_func_t)(void *opaque, char *, size_t TSRMLS_DC); + +PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg TSRMLS_DC); + +/* wrapper around php_http_buffer_chunk_buffer, which passes available chunks to passthru() */ +PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_size, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC); + +/* write chunks directly into php_http_buffer_t buffer */ +PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque TSRMLS_DC); + + +# ifdef PHP_HTTP_BUFFER_EXTENDED + +/* memcmp for php_http_buffer_t objects */ +PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer_t *left, php_http_buffer_t *right); + +/* get a complete php_http_buffer_t duplicate */ +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_copy(const php_http_buffer_t *from, php_http_buffer_t *to); + +/* merge several php_http_buffer_t objects + use like: + + php_http_buffer_t *final = php_http_buffer_merge(3, + PHP_HTTP_BUFFER_NOT_FREE(&keep), + PHP_HTTP_BUFFER_ALL_FREE(middle_ptr), + PHP_HTTP_BUFFER_VAL_FREE(&local); +*/ +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge(unsigned argc, ...); +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_ex(php_http_buffer_t *buf, unsigned argc, ...); +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_va(php_http_buffer_t *buf, unsigned argc, va_list argv); + +/* insert data at a specific position of the php_http_buffer_t */ +#define php_http_buffer_inserts(b, i, o) php_http_buffer_insert((b), (i), sizeof(i)-1, (o)) +#define php_http_buffer_insertl(b, i, o) php_http_buffer_insert((b), (i), strlen(i), (o)) +PHP_HTTP_BUFFER_API size_t php_http_buffer_insert(php_http_buffer_t *buf, const char *insert, size_t insert_len, size_t offset); +PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer_t *buf, size_t offset, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 3, 4); + +/* prepend data */ +#define php_http_buffer_prepends(b, p) php_http_buffer_prepend((b), (p), sizeof(p)-1) +#define php_http_buffer_prependl(b, p) php_http_buffer_prepend((b), (p), strlen(p)) +PHP_HTTP_BUFFER_API size_t php_http_buffer_prepend(php_http_buffer_t *buf, const char *prepend, size_t prepend_len); +PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer_t *buf, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 2, 3); + +/* get a part of the php_http_buffer_t */ +#define php_http_buffer_mid(b, o, l) php_http_buffer_sub((b), (o), (l)) +#define php_http_buffer_left(b, l) php_http_buffer_sub((b), 0, (l)) +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_right(const php_http_buffer_t *buf, size_t length); +PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_sub(const php_http_buffer_t *buf, size_t offset, size_t len); + +# endif /* PHP_HTTP_BUFFER_EXTENDED */ + +#endif /* PHP_HTTP_BUFFER_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/php_http_cache_api.h b/php_http_cache_api.h deleted file mode 100644 index 8df20a0..0000000 --- a/php_http_cache_api.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_CACHE_API_H -#define PHP_HTTP_CACHE_API_H - -#include "php_http_send_api.h" - -#include "ext/standard/crc32.h" -#include "ext/standard/sha1.h" -#include "ext/standard/md5.h" - -#ifdef HTTP_HAVE_HASH -# include "php_hash.h" -#endif - -#define http_etag_digest(d, l) _http_etag_digest((d), (l)) -static inline char *_http_etag_digest(const unsigned char *digest, int len) -{ - static const char hexdigits[17] = "0123456789abcdef"; - int i; - char *hex = emalloc(len * 2 + 1); - char *ptr = hex; - - for (i = 0; i < len; ++i) { - *ptr++ = hexdigits[digest[i] >> 4]; - *ptr++ = hexdigits[digest[i] & 0xF]; - } - *ptr = '\0'; - - return hex; -} - -#define http_etag_init() _http_etag_init(TSRMLS_C) -static inline void *_http_etag_init(TSRMLS_D) -{ - void *ctx = NULL; - char *mode = HTTP_G->etag.mode; - -#ifdef HTTP_HAVE_HASH - const php_hash_ops *eho = NULL; - - if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) { - ctx = emalloc(eho->context_size); - eho->hash_init(ctx); - } else -#endif - if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) { - ctx = emalloc(sizeof(uint)); - *((uint *) ctx) = ~0; - } else if (mode && !strcasecmp(mode, "sha1")) { - PHP_SHA1Init(ctx = emalloc(sizeof(PHP_SHA1_CTX))); - } else { - PHP_MD5Init(ctx = emalloc(sizeof(PHP_MD5_CTX))); - } - - return ctx; -} - -#define http_etag_finish(c) _http_etag_finish((c) TSRMLS_CC) -static inline char *_http_etag_finish(void *ctx TSRMLS_DC) -{ - unsigned char digest[128] = {0}; - char *etag = NULL, *mode = HTTP_G->etag.mode; - -#ifdef HTTP_HAVE_HASH - const php_hash_ops *eho = NULL; - - if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) { - eho->hash_final(digest, ctx); - etag = http_etag_digest(digest, eho->digest_size); - } else -#endif - if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) { - *((uint *) ctx) = ~*((uint *) ctx); - etag = http_etag_digest((const unsigned char *) ctx, sizeof(uint)); - } else if (mode && (!strcasecmp(mode, "sha1"))) { - PHP_SHA1Final(digest, ctx); - etag = http_etag_digest(digest, 20); - } else { - PHP_MD5Final(digest, ctx); - etag = http_etag_digest(digest, 16); - } - efree(ctx); - - return etag; -} - -#define http_etag_update(c, d, l) _http_etag_update((c), (d), (l) TSRMLS_CC) -static inline void _http_etag_update(void *ctx, const char *data_ptr, size_t data_len TSRMLS_DC) -{ - char *mode = HTTP_G->etag.mode; -#ifdef HTTP_HAVE_HASH - const php_hash_ops *eho = NULL; - - if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) { - eho->hash_update(ctx, (const unsigned char *) data_ptr, data_len); - } else -#endif - if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) { - uint i, c = *((uint *) ctx); - for (i = 0; i < data_len; ++i) { - CRC32(c, data_ptr[i]); - } - *((uint *)ctx) = c; - } else if (mode && (!strcasecmp(mode, "sha1"))) { - PHP_SHA1Update(ctx, (const unsigned char *) data_ptr, data_len); - } else { - PHP_MD5Update(ctx, (const unsigned char *) data_ptr, data_len); - } -} - -#define http_ob_etaghandler(o, l, ho, hl, m) _http_ob_etaghandler((o), (l), (ho), (hl), (m) TSRMLS_CC) -extern void _http_ob_etaghandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC); - -#define http_etag(p, l, m) _http_etag((p), (l), (m) TSRMLS_CC) -PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC); - -#define http_last_modified(p, m) _http_last_modified((p), (m) TSRMLS_CC) -PHP_HTTP_API time_t _http_last_modified(const void *data_ptr, http_send_mode data_mode TSRMLS_DC); - -#define http_match_last_modified(entry, modified) _http_match_last_modified_ex((entry), (modified), 1 TSRMLS_CC) -#define http_match_last_modified_ex(entry, modified, ep) _http_match_last_modified_ex((entry), (modified), (ep) TSRMLS_CC) -PHP_HTTP_API zend_bool _http_match_last_modified_ex(const char *entry, time_t t, zend_bool enforce_presence TSRMLS_DC); - -#define http_match_etag(entry, etag) _http_match_etag_ex((entry), (etag), 1 TSRMLS_CC) -#define http_match_etag_ex(entry, etag, ep) _http_match_etag_ex((entry), (etag), (ep) TSRMLS_CC) -PHP_HTTP_API zend_bool _http_match_etag_ex(const char *entry, const char *etag, zend_bool enforce_presence TSRMLS_DC); - -#define http_cache_last_modified(l, s, cc, ccl) _http_cache_last_modified((l), (s), (cc), (ccl) TSRMLS_CC) -PHP_HTTP_API STATUS _http_cache_last_modified(time_t last_modified, time_t send_modified, const char *cache_control, size_t cc_len TSRMLS_DC); - -#define http_cache_etag(e, el, cc, ccl) _http_cache_etag((e), (el), (cc), (ccl) TSRMLS_CC) -PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len, const char *cache_control, size_t cc_len TSRMLS_DC); - -#define http_start_ob_etaghandler() _http_start_ob_etaghandler(TSRMLS_C) -PHP_HTTP_API STATUS _http_start_ob_etaghandler(TSRMLS_D); -#define http_interrupt_ob_etaghandler() _http_interrupt_ob_etaghandler(TSRMLS_C) -PHP_HTTP_API zend_bool _http_interrupt_ob_etaghandler(TSRMLS_D); - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_client.c b/php_http_client.c new file mode 100644 index 0000000..6dced66 --- /dev/null +++ b/php_http_client.c @@ -0,0 +1,1196 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" +#include "php_http_client.h" + +#include + +/* + * array of name => php_http_client_driver_t* + */ +static HashTable php_http_client_drivers; + +STATUS php_http_client_driver_add(php_http_client_driver_t *driver) +{ + return zend_hash_add(&php_http_client_drivers, driver->name_str, driver->name_len + 1, (void *) driver, sizeof(php_http_client_driver_t), NULL); +} + +STATUS php_http_client_driver_get(const char *name_str, size_t name_len, php_http_client_driver_t *driver) +{ + php_http_client_driver_t *tmp; + + if ((name_str && SUCCESS == zend_hash_find(&php_http_client_drivers, name_str, name_len + 1, (void *) &tmp)) + || (SUCCESS == zend_hash_get_current_data(&php_http_client_drivers, (void *) &tmp))) { + *driver = *tmp; + return SUCCESS; + } + return FAILURE; +} + +static int apply_driver_list(void *p, void *arg TSRMLS_DC) +{ + php_http_client_driver_t *d = p; + zval *zname; + + MAKE_STD_ZVAL(zname); + ZVAL_STRINGL(zname, d->name_str, d->name_len, 1); + + zend_hash_next_index_insert(arg, &zname, sizeof(zval *), NULL); + return ZEND_HASH_APPLY_KEEP; +} + +void php_http_client_driver_list(HashTable *ht TSRMLS_DC) +{ + zend_hash_apply_with_argument(&php_http_client_drivers, apply_driver_list, ht TSRMLS_CC); +} + +void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite TSRMLS_DC) +{ + if (overwrite || (opts && zend_hash_num_elements(Z_ARRVAL_P(opts)))) { + zend_class_entry *this_ce = Z_OBJCE_P(getThis()); + zval *old_opts, *new_opts, **entry = NULL; + + MAKE_STD_ZVAL(new_opts); + array_init(new_opts); + old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + if (Z_TYPE_P(old_opts) == IS_ARRAY) { + array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); + } + + if (overwrite) { + if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { + Z_ADDREF_P(opts); + zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL); + } else { + zend_symtable_del(Z_ARRVAL_P(new_opts), key, len); + } + } else if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) { + array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, 0); + } else { + Z_ADDREF_P(opts); + zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL); + } + } + + zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC); + zval_ptr_dtor(&new_opts); + } +} + +void php_http_client_options_set(zval *this_ptr, zval *opts TSRMLS_DC) +{ + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + HashPosition pos; + zval *new_opts; + zend_class_entry *this_ce = Z_OBJCE_P(getThis()); + zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry TSRMLS_CC); + + MAKE_STD_ZVAL(new_opts); + array_init(new_opts); + + if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) { + zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC); + zval_ptr_dtor(&new_opts); + } else { + zval *old_opts, *add_opts, **opt; + + MAKE_STD_ZVAL(add_opts); + array_init(add_opts); + /* some options need extra attention -- thus cannot use array_merge() directly */ + FOREACH_KEYVAL(pos, opts, key, opt) { + if (key.type == HASH_KEY_IS_STRING) { +#define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s)) + if (Z_TYPE_PP(opt) == IS_ARRAY && (KEYMATCH(key, "ssl") || KEYMATCH(key, "cookies"))) { + php_http_client_options_set_subr(getThis(), key.str, key.len, *opt, 0 TSRMLS_CC); + } else if (is_client && (KEYMATCH(key, "recordHistory") || KEYMATCH(key, "responseMessageClass"))) { + zend_update_property(this_ce, getThis(), key.str, key.len-1, *opt TSRMLS_CC); + } else if (Z_TYPE_PP(opt) == IS_NULL) { + old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + if (Z_TYPE_P(old_opts) == IS_ARRAY) { + zend_symtable_del(Z_ARRVAL_P(old_opts), key.str, key.len); + } + } else { + Z_ADDREF_P(*opt); + add_assoc_zval_ex(add_opts, key.str, key.len, *opt); + } + } + } + + old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + if (Z_TYPE_P(old_opts) == IS_ARRAY) { + array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); + } + array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0); + zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC); + zval_ptr_dtor(&new_opts); + zval_ptr_dtor(&add_opts); + } +} + +void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value TSRMLS_DC) +{ + zend_class_entry *this_ce = Z_OBJCE_P(getThis()); + zval **options, *opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + + if ((Z_TYPE_P(opts) == IS_ARRAY) && (SUCCESS == zend_symtable_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) { + RETVAL_ZVAL(*options, 1, 0); + } +} + +static void queue_dtor(void *enqueued) +{ + php_http_client_enqueue_t *e = enqueued; + + if (e->dtor) { + e->dtor(e); + } +} + +php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC) +{ + php_http_client_t *free_h = NULL; + + if (!h) { + free_h = h = emalloc(sizeof(*h)); + } + memset(h, 0, sizeof(*h)); + + h->ops = ops; + if (rf) { + h->rf = rf; + } else if (ops->rsrc) { + h->rf = php_resource_factory_init(NULL, h->ops->rsrc, h, NULL); + } + zend_llist_init(&h->requests, sizeof(php_http_client_enqueue_t), queue_dtor, 0); + zend_llist_init(&h->responses, sizeof(void *), NULL, 0); + TSRMLS_SET_CTX(h->ts); + + if (h->ops->init) { + if (!(h = h->ops->init(h, init_arg))) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize client"); + if (free_h) { + efree(free_h); + } + } + } + + return h; +} + +php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to) +{ + if (from->ops->copy) { + return from->ops->copy(from, to); + } + + return NULL; +} + +void php_http_client_dtor(php_http_client_t *h) +{ + php_http_client_reset(h); + + if (h->ops->dtor) { + h->ops->dtor(h); + } + + php_resource_factory_free(&h->rf); +} + +void php_http_client_free(php_http_client_t **h) { + if (*h) { + php_http_client_dtor(*h); + efree(*h); + *h = NULL; + } +} + +STATUS php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) +{ + TSRMLS_FETCH_FROM_CTX(h->ts); + + if (h->ops->enqueue) { + if (php_http_client_enqueued(h, enqueue->request, NULL)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to enqueue request; request already in queue"); + return FAILURE; + } + return h->ops->enqueue(h, enqueue); + } + + return FAILURE; +} + +STATUS php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request) +{ + TSRMLS_FETCH_FROM_CTX(h->ts); + + if (h->ops->dequeue) { + php_http_client_enqueue_t *enqueue = php_http_client_enqueued(h, request, NULL); + + if (!enqueue) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to dequeue request; request not in queue"); + return FAILURE; + } + return h->ops->dequeue(h, enqueue); + } + return FAILURE; +} + +php_http_client_enqueue_t *php_http_client_enqueued(php_http_client_t *h, void *compare_arg, php_http_client_enqueue_cmp_func_t compare_func) +{ + zend_llist_element *el = NULL; + + if (compare_func) { + for (el = h->requests.head; el; el = el->next) { + if (compare_func((php_http_client_enqueue_t *) el->data, compare_arg)) { + break; + } + } + } else { + for (el = h->requests.head; el; el = el->next) { + if (((php_http_client_enqueue_t *) el->data)->request == compare_arg) { + break; + } + } + } + return el ? (php_http_client_enqueue_t *) el->data : NULL; +} + +STATUS php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout) +{ + if (h->ops->wait) { + return h->ops->wait(h, custom_timeout); + } + + return FAILURE; +} + +int php_http_client_once(php_http_client_t *h) +{ + if (h->ops->once) { + return h->ops->once(h); + } + + return FAILURE; +} + +STATUS php_http_client_exec(php_http_client_t *h) +{ + if (h->ops->exec) { + return h->ops->exec(h); + } + + return FAILURE; +} + +void php_http_client_reset(php_http_client_t *h) +{ + if (h->ops->reset) { + h->ops->reset(h); + } + + zend_llist_clean(&h->requests); + zend_llist_clean(&h->responses); +} + +STATUS php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg) +{ + if (h->ops->setopt) { + return h->ops->setopt(h, opt, arg); + } + + return FAILURE; +} + +STATUS php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr) +{ + if (h->ops->getopt) { + return h->ops->getopt(h, opt, arg, res_ptr); + } + return FAILURE; +} + +zend_class_entry *php_http_client_class_entry; +static zend_object_handlers php_http_client_object_handlers; + +void php_http_client_object_free(void *object TSRMLS_DC) +{ + php_http_client_object_t *o = (php_http_client_object_t *) object; + + php_http_client_free(&o->client); + zend_object_std_dtor((zend_object *) o TSRMLS_CC); + efree(o); +} + +zend_object_value php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *client, php_http_client_object_t **ptr TSRMLS_DC) +{ + php_http_client_object_t *o; + + o = ecalloc(1, sizeof(php_http_client_object_t)); + zend_object_std_init((zend_object *) o, ce TSRMLS_CC); + object_properties_init((zend_object *) o, ce); + + o->client = client; + + if (ptr) { + *ptr = o; + } + + o->zv.handle = zend_objects_store_put(o, NULL, php_http_client_object_free, NULL TSRMLS_CC); + o->zv.handlers = &php_http_client_object_handlers; + + return o->zv; +} + +zend_object_value php_http_client_object_new(zend_class_entry *ce TSRMLS_DC) +{ + return php_http_client_object_new_ex(ce, NULL, NULL TSRMLS_CC); +} + +static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response TSRMLS_DC) +{ + zval *new_hist, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0 TSRMLS_CC); + php_http_message_t *zipped = php_http_message_zip(response, request); + zend_object_value ov = php_http_message_object_new_ex(php_http_message_class_entry, zipped, NULL TSRMLS_CC); + + MAKE_STD_ZVAL(new_hist); + ZVAL_OBJVAL(new_hist, ov, 0); + + if (Z_TYPE_P(old_hist) == IS_OBJECT) { + php_http_message_object_prepend(new_hist, old_hist, 1 TSRMLS_CC); + } + + zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), new_hist TSRMLS_CC); + zval_ptr_dtor(&new_hist); +} + +static STATUS handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **request, php_http_message_t **response) +{ + zval zclient; + php_http_message_t *msg; + php_http_client_progress_state_t *progress; + TSRMLS_FETCH_FROM_CTX(client->ts); + + INIT_PZVAL(&zclient); + ZVAL_OBJVAL(&zclient, ((php_http_client_object_t*) arg)->zv, 0); + + if ((msg = *response)) { + php_http_message_object_t *msg_obj; + zval *info, *zresponse, *zrequest; + HashTable *info_ht; + + if (i_zend_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) { + handle_history(&zclient, *request, *response TSRMLS_CC); + } + + /* hard detach, redirects etc. are in the history */ + php_http_message_free(&msg->parent); + *response = NULL; + + MAKE_STD_ZVAL(zresponse); + ZVAL_OBJVAL(zresponse, php_http_message_object_new_ex(php_http_client_response_class_entry, msg, &msg_obj TSRMLS_CC), 0); + + MAKE_STD_ZVAL(zrequest); + ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1); + + php_http_message_object_prepend(zresponse, zrequest, 1 TSRMLS_CC); + + MAKE_STD_ZVAL(info); + object_init(info); + info_ht = HASH_OF(info); + php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, e->request, &info_ht); + zend_update_property(php_http_client_response_class_entry, zresponse, ZEND_STRL("transferInfo"), info TSRMLS_CC); + zval_ptr_dtor(&info); + + zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC); + zend_llist_add_element(&client->responses, &msg_obj); + + if (e->closure.fci.size) { + zval *retval = NULL; + zend_error_handling zeh; + + zend_fcall_info_argn(&e->closure.fci TSRMLS_CC, 1, &zresponse); + zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC); + zend_fcall_info_call(&e->closure.fci, &e->closure.fcc, &retval, NULL TSRMLS_CC); + zend_restore_error_handling(&zeh TSRMLS_CC); + zend_fcall_info_argn(&e->closure.fci TSRMLS_CC, 0); + + if (retval) { + if (Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval)) { + php_http_client_dequeue(client, e->request); + } + zval_ptr_dtor(&retval); + } + } + + zval_ptr_dtor(&zresponse); + zval_ptr_dtor(&zrequest); + } + + if (SUCCESS == php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, e->request, &progress)) { + progress->info = "finished"; + progress->finished = 1; + client->callback.progress.func(client->callback.progress.arg, client, e, progress); + } + + return SUCCESS; +} + +static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *progress) +{ + zval *zrequest, *zprogress, *retval = NULL, *zclient; + zend_error_handling zeh; + TSRMLS_FETCH_FROM_CTX(client->ts); + + MAKE_STD_ZVAL(zclient); + ZVAL_OBJVAL(zclient, ((php_http_client_object_t *) arg)->zv, 1); + MAKE_STD_ZVAL(zrequest); + ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1); + MAKE_STD_ZVAL(zprogress); + object_init(zprogress); + add_property_bool(zprogress, "started", progress->started); + add_property_bool(zprogress, "finished", progress->finished); + add_property_string(zprogress, "info", STR_PTR(progress->info), 1); + add_property_double(zprogress, "dltotal", progress->dl.total); + add_property_double(zprogress, "dlnow", progress->dl.now); + add_property_double(zprogress, "ultotal", progress->ul.total); + add_property_double(zprogress, "ulnow", progress->ul.now); + zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC); + zend_call_method_with_2_params(&zclient, NULL, NULL, "notify", &retval, zrequest, zprogress); + zend_restore_error_handling(&zeh TSRMLS_CC); + zval_ptr_dtor(&zclient); + zval_ptr_dtor(&zrequest); + zval_ptr_dtor(&zprogress); + if (retval) { + zval_ptr_dtor(&retval); + } +} + +static void response_dtor(void *data) +{ + php_http_message_object_t *msg_obj = *(php_http_message_object_t **) data; + TSRMLS_FETCH_FROM_CTX(msg_obj->message->ts); + + zend_objects_store_del_ref_by_handle_ex(msg_obj->zv.handle, msg_obj->zv.handlers TSRMLS_CC); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct, 0, 0, 0) + ZEND_ARG_INFO(0, driver) + ZEND_ARG_INFO(0, persistent_handle_id) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, __construct) +{ + char *driver_str = NULL, *persistent_handle_str = NULL; + int driver_len = 0, persistent_handle_len = 0; + php_http_client_driver_t driver; + php_resource_factory_t *rf = NULL; + php_http_client_object_t *obj; + zval *os; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &driver_str, &driver_len, &persistent_handle_str, &persistent_handle_len), invalid_arg, return); + + if (SUCCESS != php_http_client_driver_get(driver_str, driver_len, &driver)) { + php_http_throw(unexpected_val, "Failed to locate \"%s\" client request handler", driver_str); + return; + } + + MAKE_STD_ZVAL(os); + object_init_ex(os, spl_ce_SplObjectStorage); + zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), os TSRMLS_CC); + zval_ptr_dtor(&os); + + if (persistent_handle_len) { + char *name_str; + size_t name_len; + php_persistent_handle_factory_t *pf; + + name_len = spprintf(&name_str, 0, "http\\Client\\%s", driver.name_str); + php_http_pretty_key(name_str + sizeof("http\\Client"), driver.name_len, 1, 1); + + if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, persistent_handle_str, persistent_handle_len, NULL, NULL TSRMLS_CC))) { + rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon); + } + + efree(name_str); + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + php_http_expect(obj->client = php_http_client_init(NULL, driver.client_ops, rf, NULL TSRMLS_CC), runtime, return); + + obj->client->callback.response.func = handle_response; + obj->client->callback.response.arg = obj; + obj->client->callback.progress.func = handle_progress; + obj->client->callback.progress.arg = obj; + + obj->client->responses.dtor = response_dtor; +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_reset, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, reset) +{ + php_http_client_object_t *obj; + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + obj->iterator = 0; + php_http_client_reset(obj->client); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +static HashTable *combined_options(zval *client, zval *request TSRMLS_DC) +{ + HashTable *options; + int num_options = 0; + zval *z_roptions = NULL, *z_coptions = zend_read_property(php_http_client_class_entry, client, ZEND_STRL("options"), 0 TSRMLS_CC); + + if (Z_TYPE_P(z_coptions) == IS_ARRAY) { + num_options = zend_hash_num_elements(Z_ARRVAL_P(z_coptions)); + } + zend_call_method_with_0_params(&request, NULL, NULL, "getOptions", &z_roptions); + if (z_roptions && Z_TYPE_P(z_roptions) == IS_ARRAY) { + int num = zend_hash_num_elements(Z_ARRVAL_P(z_roptions)); + if (num > num_options) { + num_options = num; + } + } + ALLOC_HASHTABLE(options); + ZEND_INIT_SYMTABLE_EX(options, num_options, 0); + if (Z_TYPE_P(z_coptions) == IS_ARRAY) { + array_copy(Z_ARRVAL_P(z_coptions), options); + } + if (z_roptions) { + if (Z_TYPE_P(z_roptions) == IS_ARRAY) { + array_join(Z_ARRVAL_P(z_roptions), options, 0, 0); + } + zval_ptr_dtor(&z_roptions); + } + return options; +} + +static void msg_queue_dtor(php_http_client_enqueue_t *e) +{ + php_http_message_object_t *msg_obj = e->opaque; + TSRMLS_FETCH_FROM_CTX(msg_obj->message->ts); + + zend_objects_store_del_ref_by_handle_ex(msg_obj->zv.handle, msg_obj->zv.handlers TSRMLS_CC); + zend_hash_destroy(e->options); + FREE_HASHTABLE(e->options); + + if (e->closure.fci.size) { + zval_ptr_dtor(&e->closure.fci.function_name); + if (e->closure.fci.object_ptr) { + zval_ptr_dtor(&e->closure.fci.object_ptr); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enqueue, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) + ZEND_ARG_INFO(0, callable) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, enqueue) +{ + zval *request; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; + php_http_client_object_t *obj; + php_http_message_object_t *msg_obj; + php_http_client_enqueue_t q; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|f", &request, php_http_client_request_class_entry, &fci, &fcc), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + msg_obj = zend_object_store_get_object(request TSRMLS_CC); + + if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) { + php_http_throw(bad_method_call, "Failed to enqueue request; request already in queue", NULL); + return; + } + + q.request = msg_obj->message; + q.options = combined_options(getThis(), request TSRMLS_CC); + q.dtor = msg_queue_dtor; + q.opaque = msg_obj; + q.closure.fci = fci; + q.closure.fcc = fcc; + + if (fci.size) { + Z_ADDREF_P(fci.function_name); + if (fci.object_ptr) { + Z_ADDREF_P(fci.object_ptr); + } + } + + zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC); + + php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime, + msg_queue_dtor(&q); + return; + ); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_dequeue, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, dequeue) +{ + zval *request; + php_http_client_object_t *obj; + php_http_message_object_t *msg_obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_class_entry), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + msg_obj = zend_object_store_get_object(request TSRMLS_CC); + + if (!php_http_client_enqueued(obj->client, msg_obj->message, NULL)) { + php_http_throw(bad_method_call, "Failed to dequeue request; request not in queue", NULL); + return; + } + + php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_requeue, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) + ZEND_ARG_INFO(0, callable) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, requeue) +{ + zval *request; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; + php_http_client_object_t *obj; + php_http_message_object_t *msg_obj; + php_http_client_enqueue_t q; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|f", &request, php_http_client_request_class_entry, &fci, &fcc), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + msg_obj = zend_object_store_get_object(request TSRMLS_CC); + + if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) { + php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return); + } + + q.request = msg_obj->message; + q.options = combined_options(getThis(), request TSRMLS_CC); + q.dtor = msg_queue_dtor; + q.opaque = msg_obj; + q.closure.fci = fci; + q.closure.fcc = fcc; + + if (fci.size) { + Z_ADDREF_P(fci.function_name); + if (fci.object_ptr) { + Z_ADDREF_P(fci.object_ptr); + } + } + + zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC); + + php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime, + msg_queue_dtor(&q); + return; + ); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_count, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, count) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + RETVAL_LONG(zend_llist_count(&obj->client->requests)); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getResponse, 0, 0, 0) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getResponse) +{ + zval *zrequest = NULL; + php_http_client_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O", &zrequest, php_http_client_request_class_entry), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zrequest) { + /* lookup the response with the request */ + zend_llist_element *el = NULL; + php_http_message_object_t *req_obj = zend_object_store_get_object(zrequest TSRMLS_CC); + + for (el = obj->client->responses.head; el; el = el->next) { + php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data; + + if (response_obj->message->parent == req_obj->message) { + RETURN_OBJVAL(response_obj->zv, 1); + } + } + + /* not found for the request! */ + php_http_throw(unexpected_val, "Could not find response for the request", NULL); + return; + } + + /* pop off the last response */ + if (obj->client->responses.tail) { + php_http_message_object_t *response_obj = *(php_http_message_object_t **) obj->client->responses.tail->data; + + /* pop off and go */ + if (response_obj) { + RETVAL_OBJVAL(response_obj->zv, 1); + zend_llist_remove_tail(&obj->client->responses); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getHistory, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getHistory) +{ + zval *zhistory; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + zhistory = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC); + RETVAL_ZVAL(zhistory, 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_send, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, send) +{ + php_http_client_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + php_http_expect(SUCCESS == php_http_client_exec(obj->client), runtime, return); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_once, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, once) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_BOOL(0 < php_http_client_once(obj->client)); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_wait, 0, 0, 0) + ZEND_ARG_INFO(0, timeout) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, wait) +{ + double timeout = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) { + struct timeval timeout_val; + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + timeout_val.tv_sec = (time_t) timeout; + timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC; + + RETURN_BOOL(SUCCESS == php_http_client_wait(obj->client, timeout > 0 ? &timeout_val : NULL)); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enablePipelining, 0, 0, 0) + ZEND_ARG_INFO(0, enable) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, enablePipelining) +{ + zend_bool enable = 1; + php_http_client_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, &enable), unexpected_val, return); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enableEvents, 0, 0, 0) + ZEND_ARG_INFO(0, enable) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, enableEvents) +{ + zend_bool enable = 1; + php_http_client_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_USE_EVENTS, &enable), unexpected_val, return); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +static int notify(zend_object_iterator *iter, void *puser TSRMLS_DC) +{ + zval **observer = NULL, ***args = puser; + + iter->funcs->get_current_data(iter, &observer TSRMLS_CC); + if (observer) { + return php_http_method_call(*observer, ZEND_STRL("update"), args[2]?3:args[1]?2:args[0]?1:0, args, NULL TSRMLS_CC); + } + return FAILURE; +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify, 0, 0, 0) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, notify) +{ + zval *request = NULL, *zprogress = NULL, *observers, **args[3]; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!o!", &request, php_http_client_request_class_entry, &zprogress), invalid_arg, return); + + observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); + + if (Z_TYPE_P(observers) != IS_OBJECT) { + php_http_throw(unexpected_val, "Observer storage is corrupted", NULL); + return; + } + + Z_ADDREF_P(getThis()); + args[0] = &getThis(); + if (request) { + Z_ADDREF_P(request); + } + args[1] = &request; + if (zprogress) { + Z_ADDREF_P(zprogress); + } + args[2] = &zprogress; + spl_iterator_apply(observers, notify, args TSRMLS_CC); + zval_ptr_dtor(&getThis()); + if (request) { + zval_ptr_dtor(&request); + } + if (zprogress) { + zval_ptr_dtor(&zprogress); + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, attach) +{ + zval *observers, *observer, *retval = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver), invalid_arg, return); + + observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); + + if (Z_TYPE_P(observers) != IS_OBJECT) { + php_http_throw(unexpected_val, "Observer storage is corrupted", NULL); + return; + } + + zend_call_method_with_1_params(&observers, NULL, NULL, "attach", &retval, observer); + if (retval) { + zval_ptr_dtor(&retval); + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, detach) +{ + zval *observers, *observer, *retval = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver), invalid_arg, return); + + observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); + + if (Z_TYPE_P(observers) != IS_OBJECT) { + php_http_throw(unexpected_val, "Observer storage is corrupted", NULL); + return; + } + + zend_call_method_with_1_params(&observers, NULL, NULL, "detach", &retval, observer); + if (retval) { + zval_ptr_dtor(&retval); + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getObservers, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getObservers) +{ + zval *observers; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); + + if (Z_TYPE_P(observers) != IS_OBJECT) { + php_http_throw(unexpected_val, "Observer storage is corrupted", NULL); + return; + } + + RETVAL_ZVAL(observers, 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getProgressInfo, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getProgressInfo) +{ + zval *request; + php_http_client_object_t *obj; + php_http_message_object_t *req_obj; + php_http_client_progress_state_t *progress; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_class_entry), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + req_obj = zend_object_store_get_object(request TSRMLS_CC); + + php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, req_obj->message, &progress), unexpected_val, return); + + object_init(return_value); + add_property_bool(return_value, "started", progress->started); + add_property_bool(return_value, "finished", progress->finished); + add_property_string(return_value, "info", STR_PTR(progress->info), 1); + add_property_double(return_value, "dltotal", progress->dl.total); + add_property_double(return_value, "dlnow", progress->dl.now); + add_property_double(return_value, "ultotal", progress->ul.total); + add_property_double(return_value, "ulnow", progress->ul.now); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getTransferInfo, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getTransferInfo) +{ + zval *request; + HashTable *info; + php_http_client_object_t *obj; + php_http_message_object_t *req_obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_class_entry), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + req_obj = zend_object_store_get_object(request TSRMLS_CC); + + object_init(return_value); + info = HASH_OF(return_value); + php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, req_obj->message, &info), unexpected_val, return); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setOptions, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, options, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, setOptions) +{ + zval *opts = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return); + + php_http_client_options_set(getThis(), opts TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getOptions, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getOptions) +{ + if (SUCCESS == zend_parse_parameters_none()) { + zval *options = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + RETVAL_ZVAL(options, 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setSslOptions, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, ssl_option, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, setSslOptions) +{ + zval *opts = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return); + + php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 1 TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addSslOptions, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, ssl_options, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, addSslOptions) +{ + zval *opts = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return); + + php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 0 TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getSslOptions, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getSslOptions) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_client_options_get_subr(getThis(), ZEND_STRS("ssl"), return_value TSRMLS_CC); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setCookies, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, cookies, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, setCookies) +{ + zval *opts = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return); + + php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 1 TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addCookies, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, cookies, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, addCookies) +{ + zval *opts = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return); + + php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 0 TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getCookies, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getCookies) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_client_options_get_subr(getThis(), ZEND_STRS("cookies"), return_value TSRMLS_CC); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableDrivers, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getAvailableDrivers) { + if (SUCCESS == zend_parse_parameters_none()) { + array_init(return_value); + php_http_client_driver_list(Z_ARRVAL_P(return_value) TSRMLS_CC); + } +} + +static zend_function_entry php_http_client_methods[] = { + PHP_ME(HttpClient, __construct, ai_HttpClient_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpClient, reset, ai_HttpClient_reset, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, enqueue, ai_HttpClient_enqueue, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, dequeue, ai_HttpClient_dequeue, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, requeue, ai_HttpClient_requeue, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, count, ai_HttpClient_count, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, send, ai_HttpClient_send, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, once, ai_HttpClient_once, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, wait, ai_HttpClient_wait, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getResponse, ai_HttpClient_getResponse, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getHistory, ai_HttpClient_getHistory, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, enablePipelining, ai_HttpClient_enablePipelining, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, enableEvents, ai_HttpClient_enableEvents, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, notify, ai_HttpClient_notify, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, attach, ai_HttpClient_attach, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, detach, ai_HttpClient_detach, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getObservers, ai_HttpClient_getObservers, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getProgressInfo, ai_HttpClient_getProgressInfo, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getTransferInfo, ai_HttpClient_getTransferInfo, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, setOptions, ai_HttpClient_setOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getOptions, ai_HttpClient_getOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, setSslOptions, ai_HttpClient_setSslOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, addSslOptions, ai_HttpClient_addSslOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getSslOptions, ai_HttpClient_getSslOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, setCookies, ai_HttpClient_setCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, addCookies, ai_HttpClient_addCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getCookies, ai_HttpClient_getCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getAvailableDrivers, ai_HttpClient_getAvailableDrivers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + EMPTY_FUNCTION_ENTRY +}; + +PHP_MINIT_FUNCTION(http_client) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "Client", php_http_client_methods); + php_http_client_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC); + php_http_client_class_entry->create_object = php_http_client_object_new; + zend_class_implements(php_http_client_class_entry TSRMLS_CC, 2, spl_ce_SplSubject, spl_ce_Countable); + memcpy(&php_http_client_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + php_http_client_object_handlers.clone_obj = NULL; + zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE TSRMLS_CC); + zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); + + zend_hash_init(&php_http_client_drivers, 2, NULL, NULL, 1); + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(http_client) +{ + zend_hash_destroy(&php_http_client_drivers); + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_client.h b/php_http_client.h new file mode 100644 index 0000000..9bc5295 --- /dev/null +++ b/php_http_client.h @@ -0,0 +1,156 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_CLIENT_H +#define PHP_HTTP_CLIENT_H + +typedef enum php_http_client_setopt_opt { + PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, + PHP_HTTP_CLIENT_OPT_USE_EVENTS, +} php_http_client_setopt_opt_t; + +typedef enum php_http_client_getopt_opt { + PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, /* php_http_client_progress_state_t** */ + PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, /* HashTable* */ +} php_http_client_getopt_opt_t; + +typedef struct php_http_client_enqueue { + php_http_message_t *request; /* unique */ + HashTable *options; + void (*dtor)(struct php_http_client_enqueue *); + void *opaque; + struct { + zend_fcall_info fci; + zend_fcall_info_cache fcc; + } closure; +} php_http_client_enqueue_t; + +typedef struct php_http_client *(*php_http_client_init_func_t)(struct php_http_client *p, void *init_arg); +typedef struct php_http_client *(*php_http_client_copy_func_t)(struct php_http_client *from, struct php_http_client *to); +typedef void (*php_http_client_dtor_func_t)(struct php_http_client *p); +typedef void (*php_http_client_reset_func_t)(struct php_http_client *p); +typedef STATUS (*php_http_client_exec_func_t)(struct php_http_client *p); +typedef int (*php_http_client_once_func_t)(struct php_http_client *p); +typedef STATUS (*php_http_client_wait_func_t)(struct php_http_client *p, struct timeval *custom_timeout); +typedef STATUS (*php_http_client_enqueue_func_t)(struct php_http_client *p, php_http_client_enqueue_t *enqueue); +typedef STATUS (*php_http_client_dequeue_func_t)(struct php_http_client *p, php_http_client_enqueue_t *enqueue); +typedef STATUS (*php_http_client_setopt_func_t)(struct php_http_client *p, php_http_client_setopt_opt_t opt, void *arg); +typedef STATUS (*php_http_client_getopt_func_t)(struct php_http_client *h, php_http_client_getopt_opt_t opt, void *arg, void **res); + +typedef struct php_http_client_ops { + php_resource_factory_ops_t *rsrc; + php_http_client_init_func_t init; + php_http_client_copy_func_t copy; + php_http_client_dtor_func_t dtor; + php_http_client_reset_func_t reset; + php_http_client_exec_func_t exec; + php_http_client_wait_func_t wait; + php_http_client_once_func_t once; + php_http_client_enqueue_func_t enqueue; + php_http_client_dequeue_func_t dequeue; + php_http_client_setopt_func_t setopt; + php_http_client_getopt_func_t getopt; +} php_http_client_ops_t; + +typedef struct php_http_client_driver { + const char *name_str; + size_t name_len; + php_http_client_ops_t *client_ops; +} php_http_client_driver_t; + +PHP_HTTP_API STATUS php_http_client_driver_add(php_http_client_driver_t *driver); +PHP_HTTP_API STATUS php_http_client_driver_get(const char *name_str, size_t name_len, php_http_client_driver_t *driver); + +typedef struct php_http_client_progress_state { + struct { + double now; + double total; + } ul; + struct { + double now; + double total; + } dl; + const char *info; + unsigned started:1; + unsigned finished:1; +} php_http_client_progress_state_t; + +typedef STATUS (*php_http_client_response_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_message_t **request, php_http_message_t **response); +typedef void (*php_http_client_progress_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *state); + +typedef struct php_http_client { + void *ctx; + php_resource_factory_t *rf; + php_http_client_ops_t *ops; + + struct { + struct { + php_http_client_response_callback_t func; + void *arg; + } response; + struct { + php_http_client_progress_callback_t func; + void *arg; + } progress; + } callback; + + zend_llist requests; + zend_llist responses; + +#ifdef ZTS + void ***ts; +#endif +} php_http_client_t; + +PHP_HTTP_API zend_class_entry *php_http_client_class_entry; + +typedef struct php_http_client_object { + zend_object zo; + zend_object_value zv; + php_http_client_t *client; + long iterator; +} php_http_client_object_t; + +PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC); +PHP_HTTP_API php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to); +PHP_HTTP_API void php_http_client_dtor(php_http_client_t *h); +PHP_HTTP_API void php_http_client_free(php_http_client_t **h); + +PHP_HTTP_API STATUS php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue); +PHP_HTTP_API STATUS php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request); + +PHP_HTTP_API STATUS php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout); +PHP_HTTP_API int php_http_client_once(php_http_client_t *h); + +PHP_HTTP_API STATUS php_http_client_exec(php_http_client_t *h); +PHP_HTTP_API void php_http_client_reset(php_http_client_t *h); + +PHP_HTTP_API STATUS php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg); +PHP_HTTP_API STATUS php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr); + +typedef int (*php_http_client_enqueue_cmp_func_t)(php_http_client_enqueue_t *cmp, void *arg); +/* compare with request message pointer if compare_func is NULL */ +PHP_HTTP_API php_http_client_enqueue_t *php_http_client_enqueued(php_http_client_t *h, void *compare_arg, php_http_client_enqueue_cmp_func_t compare_func); + +PHP_MINIT_FUNCTION(http_client); +PHP_MSHUTDOWN_FUNCTION(http_client); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_client_curl.c b/php_http_client_curl.c new file mode 100644 index 0000000..fbb950a --- /dev/null +++ b/php_http_client_curl.c @@ -0,0 +1,2006 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" +#include "php_http_client.h" + +#if PHP_HTTP_HAVE_CURL + +#if PHP_HTTP_HAVE_EVENT +# include +# if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000) +# define event_base_new event_init +# define event_assign(e, b, s, a, cb, d) do {\ + event_set(e, s, a, cb, d); \ + event_base_set(b, e); \ + } while(0) +# endif +# ifndef DBG_EVENTS +# define DBG_EVENTS 0 +# endif +#endif + +typedef struct php_http_client_curl { + CURLM *handle; + + int unfinished; /* int because of curl_multi_perform() */ + +#if PHP_HTTP_HAVE_EVENT + struct event *timeout; + unsigned useevents:1; +#endif +} php_http_client_curl_t; + +typedef struct php_http_client_curl_handler { + CURL *handle; + php_resource_factory_t *rf; + php_http_client_t *client; + php_http_client_progress_state_t progress; + + php_http_client_enqueue_t queue; + + struct { + php_http_message_parser_t *parser; + php_http_message_t *message; + php_http_buffer_t *buffer; + } request; + + struct { + php_http_message_parser_t *parser; + php_http_message_t *message; + php_http_buffer_t *buffer; + } response; + + struct { + HashTable cache; + + struct curl_slist *headers; + struct curl_slist *resolve; + php_http_buffer_t cookies; + php_http_buffer_t ranges; + + long redirects; + unsigned range_request:1; + unsigned encode_cookies:1; + + struct { + uint count; + double delay; + } retry; + + } options; + +} php_http_client_curl_handler_t; + +typedef struct php_http_curle_storage { + char *url; + char *cookiestore; + char errorbuffer[0x100]; +} php_http_curle_storage_t; + +static inline php_http_curle_storage_t *php_http_curle_get_storage(CURL *ch) { + php_http_curle_storage_t *st = NULL; + + curl_easy_getinfo(ch, CURLINFO_PRIVATE, &st); + + if (!st) { + st = pecalloc(1, sizeof(*st), 1); + curl_easy_setopt(ch, CURLOPT_PRIVATE, st); + curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer); + } + + return st; +} + +static void *php_http_curle_ctor(void *opaque, void *init_arg TSRMLS_DC) +{ + void *ch; + + if ((ch = curl_easy_init())) { + php_http_curle_get_storage(ch); + return ch; + } + return NULL; +} + +static void *php_http_curle_copy(void *opaque, void *handle TSRMLS_DC) +{ + void *ch; + + if ((ch = curl_easy_duphandle(handle))) { + curl_easy_reset(ch); + php_http_curle_get_storage(ch); + return ch; + } + return NULL; +} + +static void php_http_curle_dtor(void *opaque, void *handle TSRMLS_DC) +{ + php_http_curle_storage_t *st = php_http_curle_get_storage(handle); + + curl_easy_cleanup(handle); + + if (st) { + if (st->url) { + pefree(st->url, 1); + } + if (st->cookiestore) { + pefree(st->cookiestore, 1); + } + pefree(st, 1); + } +} + +static php_resource_factory_ops_t php_http_curle_resource_factory_ops = { + php_http_curle_ctor, + php_http_curle_copy, + php_http_curle_dtor +}; + +static void *php_http_curlm_ctor(void *opaque, void *init_arg TSRMLS_DC) +{ + return curl_multi_init(); +} + +static void php_http_curlm_dtor(void *opaque, void *handle TSRMLS_DC) +{ + curl_multi_cleanup(handle); +} + +static php_resource_factory_ops_t php_http_curlm_resource_factory_ops = { + php_http_curlm_ctor, + NULL, + php_http_curlm_dtor +}; + +/* curl callbacks */ + +static size_t php_http_curle_read_callback(void *data, size_t len, size_t n, void *ctx) +{ + php_http_message_body_t *body = ctx; + + if (body) { + TSRMLS_FETCH_FROM_CTX(body->ts); + return php_stream_read(php_http_message_body_stream(body), data, len * n); + } + return 0; +} + +static int php_http_curle_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow) +{ + php_http_client_curl_handler_t *h = ctx; + zend_bool update = 0; + + if (h->progress.dl.total != dltotal + || h->progress.dl.now != dlnow + || h->progress.ul.total != ultotal + || h->progress.ul.now != ulnow + ) { + update = 1; + + h->progress.dl.total = dltotal; + h->progress.dl.now = dlnow; + h->progress.ul.total = ultotal; + h->progress.ul.now = ulnow; + } + + if (update && h->client->callback.progress.func) { + h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress); + } + + return 0; +} + +static curlioerr php_http_curle_ioctl_callback(CURL *ch, curliocmd cmd, void *ctx) +{ + php_http_message_body_t *body = ctx; + + if (cmd != CURLIOCMD_RESTARTREAD) { + return CURLIOE_UNKNOWNCMD; + } + + if (body) { + TSRMLS_FETCH_FROM_CTX(body->ts); + + if (SUCCESS == php_stream_rewind(php_http_message_body_stream(body))) { + return CURLIOE_OK; + } + } + + return CURLIOE_FAILRESTART; +} + +static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx) +{ + php_http_client_curl_handler_t *h = ctx; + unsigned flags = 0; + + /* catch progress */ + switch (type) { + case CURLINFO_TEXT: + if (data[0] == '-') { + } else if (php_memnstr(data, ZEND_STRL("Adding handle:"), data + length)) { + h->progress.info = "setup"; + } else if (php_memnstr(data, ZEND_STRL("addHandle"), data + length)) { + h->progress.info = "setup"; + } else if (php_memnstr(data, ZEND_STRL("About to connect"), data + length)) { + h->progress.info = "resolve"; + } else if (php_memnstr(data, ZEND_STRL("Trying"), data + length)) { + h->progress.info = "connect"; + } else if (php_memnstr(data, ZEND_STRL("Found bundle for host"), data + length)) { + h->progress.info = "connect"; + } else if (php_memnstr(data, ZEND_STRL("Connected"), data + length)) { + h->progress.info = "connected"; + } else if (php_memnstr(data, ZEND_STRL("Re-using existing connection!"), data + length)) { + h->progress.info = "connected"; + } else if (php_memnstr(data, ZEND_STRL("blacklisted"), data + length)) { + h->progress.info = "blacklist check"; + } else if (php_memnstr(data, ZEND_STRL("SSL"), data + length)) { + h->progress.info = "ssl negotiation"; + } else if (php_memnstr(data, ZEND_STRL("left intact"), data + length)) { + h->progress.info = "not disconnected"; + } else if (php_memnstr(data, ZEND_STRL("closed"), data + length)) { + h->progress.info = "disconnected"; + } else if (php_memnstr(data, ZEND_STRL("Issue another request"), data + length)) { + h->progress.info = "redirect"; + } else if (php_memnstr(data, ZEND_STRL("Operation timed out"), data + length)) { + h->progress.info = "timeout"; + } else { +#if PHP_DEBUG + h->progress.info = data; +#endif + } + if (h->client->callback.progress.func) { + h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress); + } + break; + case CURLINFO_HEADER_OUT: + case CURLINFO_DATA_OUT: + case CURLINFO_SSL_DATA_OUT: + h->progress.info = "send"; + break; + case CURLINFO_HEADER_IN: + case CURLINFO_DATA_IN: + case CURLINFO_SSL_DATA_IN: + h->progress.info = "receive"; + break; + default: + break; + } + /* process data */ + switch (type) { + case CURLINFO_HEADER_IN: + case CURLINFO_DATA_IN: + php_http_buffer_append(h->response.buffer, data, length); + + if (h->options.redirects) { + flags |= PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS; + } + + if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->response.parser, h->response.buffer, flags, &h->response.message)) { + return -1; + } + break; + + case CURLINFO_HEADER_OUT: + case CURLINFO_DATA_OUT: + php_http_buffer_append(h->request.buffer, data, length); + + if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->request.parser, h->request.buffer, flags, &h->request.message)) { + return -1; + } + break; + default: + break; + } + +#if 0 + /* debug */ + _dpf(type, data, length); +#endif + + return 0; +} + +static int php_http_curle_dummy_callback(char *data, size_t n, size_t l, void *s) +{ + return n*l; +} + +static STATUS php_http_curle_get_info(CURL *ch, HashTable *info) +{ + char *c; + long l; + double d; + struct curl_slist *s, *p; + zval *subarray, array; + INIT_PZVAL_ARRAY(&array, info); + + /* BEGIN::CURLINFO */ + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_URL, &c)) { + add_assoc_string_ex(&array, "effective_url", sizeof("effective_url"), c ? c : "", 1); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &l)) { + add_assoc_long_ex(&array, "response_code", sizeof("response_code"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TOTAL_TIME, &d)) { + add_assoc_double_ex(&array, "total_time", sizeof("total_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NAMELOOKUP_TIME, &d)) { + add_assoc_double_ex(&array, "namelookup_time", sizeof("namelookup_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONNECT_TIME, &d)) { + add_assoc_double_ex(&array, "connect_time", sizeof("connect_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRETRANSFER_TIME, &d)) { + add_assoc_double_ex(&array, "pretransfer_time", sizeof("pretransfer_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_UPLOAD, &d)) { + add_assoc_double_ex(&array, "size_upload", sizeof("size_upload"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_DOWNLOAD, &d)) { + add_assoc_double_ex(&array, "size_download", sizeof("size_download"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_DOWNLOAD, &d)) { + add_assoc_double_ex(&array, "speed_download", sizeof("speed_download"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_UPLOAD, &d)) { + add_assoc_double_ex(&array, "speed_upload", sizeof("speed_upload"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HEADER_SIZE, &l)) { + add_assoc_long_ex(&array, "header_size", sizeof("header_size"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REQUEST_SIZE, &l)) { + add_assoc_long_ex(&array, "request_size", sizeof("request_size"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_VERIFYRESULT, &l)) { + add_assoc_long_ex(&array, "ssl_verifyresult", sizeof("ssl_verifyresult"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_FILETIME, &l)) { + add_assoc_long_ex(&array, "filetime", sizeof("filetime"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) { + add_assoc_double_ex(&array, "content_length_download", sizeof("content_length_download"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) { + add_assoc_double_ex(&array, "content_length_upload", sizeof("content_length_upload"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME, &d)) { + add_assoc_double_ex(&array, "starttransfer_time", sizeof("starttransfer_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_TYPE, &c)) { + add_assoc_string_ex(&array, "content_type", sizeof("content_type"), c ? c : "", 1); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_TIME, &d)) { + add_assoc_double_ex(&array, "redirect_time", sizeof("redirect_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_COUNT, &l)) { + add_assoc_long_ex(&array, "redirect_count", sizeof("redirect_count"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_CONNECTCODE, &l)) { + add_assoc_long_ex(&array, "connect_code", sizeof("connect_code"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTPAUTH_AVAIL, &l)) { + add_assoc_long_ex(&array, "httpauth_avail", sizeof("httpauth_avail"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXYAUTH_AVAIL, &l)) { + add_assoc_long_ex(&array, "proxyauth_avail", sizeof("proxyauth_avail"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_OS_ERRNO, &l)) { + add_assoc_long_ex(&array, "os_errno", sizeof("os_errno"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NUM_CONNECTS, &l)) { + add_assoc_long_ex(&array, "num_connects", sizeof("num_connects"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_ENGINES, &s)) { + MAKE_STD_ZVAL(subarray); + array_init(subarray); + for (p = s; p; p = p->next) { + if (p->data) { + add_next_index_string(subarray, p->data, 1); + } + } + add_assoc_zval_ex(&array, "ssl_engines", sizeof("ssl_engines"), subarray); + curl_slist_free_all(s); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_COOKIELIST, &s)) { + MAKE_STD_ZVAL(subarray); + array_init(subarray); + for (p = s; p; p = p->next) { + if (p->data) { + add_next_index_string(subarray, p->data, 1); + } + } + add_assoc_zval_ex(&array, "cookies", sizeof("cookies"), subarray); + curl_slist_free_all(s); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_URL, &c)) { + add_assoc_string_ex(&array, "redirect_url", sizeof("redirect_url"), c ? c : "", 1); + } +#if PHP_HTTP_CURL_VERSION(7,19,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_IP, &c)) { + add_assoc_string_ex(&array, "primary_ip", sizeof("primary_ip"), c ? c : "", 1); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,19,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_APPCONNECT_TIME, &d)) { + add_assoc_double_ex(&array, "appconnect_time", sizeof("appconnect_time"), d); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,19,4) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONDITION_UNMET, &l)) { + add_assoc_long_ex(&array, "condition_unmet", sizeof("condition_unmet"), l); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,21,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_PORT, &l)) { + add_assoc_long_ex(&array, "primary_port", sizeof("primary_port"), l); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,21,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_IP, &c)) { + add_assoc_string_ex(&array, "local_ip", sizeof("local_ip"), c ? c : "", 1); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,21,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_PORT, &l)) { + add_assoc_long_ex(&array, "local_port", sizeof("local_port"), l); + } +#endif + + /* END::CURLINFO */ + +#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL) + { + int i; + zval *ci_array; + struct curl_certinfo *ci; + char *colon, *keyname; + + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CERTINFO, &ci)) { + MAKE_STD_ZVAL(ci_array); + array_init(ci_array); + + for (i = 0; i < ci->num_of_certs; ++i) { + s = ci->certinfo[i]; + + MAKE_STD_ZVAL(subarray); + array_init(subarray); + for (p = s; p; p = p->next) { + if (p->data) { + if ((colon = strchr(p->data, ':'))) { + keyname = estrndup(p->data, colon - p->data); + add_assoc_string_ex(subarray, keyname, colon - p->data + 1, colon + 1, 1); + efree(keyname); + } else { + add_next_index_string(subarray, p->data, 1); + } + } + } + add_next_index_zval(ci_array, subarray); + } + add_assoc_zval_ex(&array, "certinfo", sizeof("certinfo"), ci_array); + } + } +#endif + add_assoc_string_ex(&array, "error", sizeof("error"), php_http_curle_get_storage(ch)->errorbuffer, 1); + + return SUCCESS; +} + +static int compare_queue(php_http_client_enqueue_t *e, void *handle) +{ + return handle == ((php_http_client_curl_handler_t *) e->opaque)->handle; +} + +static void php_http_curlm_responsehandler(php_http_client_t *context) +{ + int remaining = 0; + php_http_client_enqueue_t *enqueue; + php_http_client_curl_t *curl = context->ctx; + TSRMLS_FETCH_FROM_CTX(context->ts); + + do { + CURLMsg *msg = curl_multi_info_read(curl->handle, &remaining); + + if (msg && CURLMSG_DONE == msg->msg) { + if (CURLE_OK != msg->data.result) { + php_http_curle_storage_t *st = php_http_curle_get_storage(msg->easy_handle); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s; %s (%s)", curl_easy_strerror(msg->data.result), STR_PTR(st->errorbuffer), STR_PTR(st->url)); + } + + if ((enqueue = php_http_client_enqueued(context, msg->easy_handle, compare_queue))) { + php_http_client_curl_handler_t *handler = enqueue->opaque; + + context->callback.response.func(context->callback.response.arg, context, &handler->queue, &handler->request.message, &handler->response.message); + } + } + } while (remaining); +} + +#if PHP_HTTP_HAVE_EVENT + +typedef struct php_http_curlm_event { + struct event evnt; + php_http_client_t *context; +} php_http_curlm_event_t; + +static inline int etoca(short action) { + switch (action & (EV_READ|EV_WRITE)) { + case EV_READ: + return CURL_CSELECT_IN; + break; + case EV_WRITE: + return CURL_CSELECT_OUT; + break; + case EV_READ|EV_WRITE: + return CURL_CSELECT_IN|CURL_CSELECT_OUT; + break; + default: + return 0; + } +} + +static void php_http_curlm_timeout_callback(int socket, short action, void *event_data) +{ + php_http_client_t *context = event_data; + php_http_client_curl_t *curl = context->ctx; + +#if DBG_EVENTS + fprintf(stderr, "T"); +#endif + if (curl->useevents) { + CURLMcode rc; + TSRMLS_FETCH_FROM_CTX(context->ts); + + /* ignore and use -1,0 on timeout */ + (void) socket; + (void) action; + + while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished))); + + if (CURLM_OK != rc) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc)); + } + + php_http_curlm_responsehandler(context); + } +} + +static void php_http_curlm_event_callback(int socket, short action, void *event_data) +{ + php_http_client_t *context = event_data; + php_http_client_curl_t *curl = context->ctx; + +#if DBG_EVENTS + fprintf(stderr, "E"); +#endif + if (curl->useevents) { + CURLMcode rc = CURLM_OK; + TSRMLS_FETCH_FROM_CTX(context->ts); + + while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, socket, etoca(action), &curl->unfinished))); + + if (CURLM_OK != rc) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc)); + } + + php_http_curlm_responsehandler(context); + + /* remove timeout if there are no transfers left */ + if (!curl->unfinished && event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) { + event_del(curl->timeout); + } + } +} + +static int php_http_curlm_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data) +{ + php_http_client_t *context = socket_data; + php_http_client_curl_t *curl = context->ctx; + +#if DBG_EVENTS + fprintf(stderr, "S"); +#endif + if (curl->useevents) { + int events = EV_PERSIST; + php_http_curlm_event_t *ev = assign_data; + TSRMLS_FETCH_FROM_CTX(context->ts); + + if (!ev) { + ev = ecalloc(1, sizeof(php_http_curlm_event_t)); + ev->context = context; + curl_multi_assign(curl->handle, sock, ev); + } else { + event_del(&ev->evnt); + } + + switch (action) { + case CURL_POLL_IN: + events |= EV_READ; + break; + case CURL_POLL_OUT: + events |= EV_WRITE; + break; + case CURL_POLL_INOUT: + events |= EV_READ|EV_WRITE; + break; + + case CURL_POLL_REMOVE: + efree(ev); + /* no break */ + case CURL_POLL_NONE: + return 0; + + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action); + return -1; + } + + event_assign(&ev->evnt, PHP_HTTP_G->curl.event_base, sock, events, php_http_curlm_event_callback, context); + event_add(&ev->evnt, NULL); + } + + return 0; +} + +static void php_http_curlm_timer_callback(CURLM *multi, long timeout_ms, void *timer_data) +{ + php_http_client_t *context = timer_data; + php_http_client_curl_t *curl = context->ctx; + +#if DBG_EVENTS + fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms); +#endif + if (curl->useevents) { + + if (timeout_ms < 0) { + php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, context); + } else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) { + struct timeval timeout; + TSRMLS_FETCH_FROM_CTX(context->ts); + + if (!event_initialized(curl->timeout)) { + event_assign(curl->timeout, PHP_HTTP_G->curl.event_base, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, context); + } else if (event_pending(curl->timeout, EV_TIMEOUT, NULL)) { + event_del(curl->timeout); + } + + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + + event_add(curl->timeout, &timeout); + } + } +} + +#endif /* HAVE_EVENT */ + +/* curl options */ + +static php_http_options_t php_http_curle_options; + +#define PHP_HTTP_CURLE_OPTION_CHECK_STRLEN 0x0001 +#define PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR 0x0002 +#define PHP_HTTP_CURLE_OPTION_TRANSFORM_MS 0x0004 + +static STATUS php_http_curle_option_set_ssl_verifyhost(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, Z_BVAL_P(val) ? 2 : 0)) { + return FAILURE; + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_cookiestore(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + + if (val) { + php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle); + + if (storage->cookiestore) { + pefree(storage->cookiestore, 1); + } + storage->cookiestore = pestrndup(Z_STRVAL_P(val), Z_STRLEN_P(val), 1); + if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore) + || CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore) + ) { + return FAILURE; + } + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_cookies(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (val && Z_TYPE_P(val) != IS_NULL) { + if (curl->options.encode_cookies) { + if (SUCCESS == php_http_url_encode_hash_ex(HASH_OF(val), &curl->options.cookies, ZEND_STRL(";"), ZEND_STRL("="), NULL, 0 TSRMLS_CC)) { + php_http_buffer_fix(&curl->options.cookies); + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) { + return FAILURE; + } + } else { + return FAILURE; + } + } else { + HashPosition pos; + php_http_array_hashkey_t cookie_key = php_http_array_hashkey_init(0); + zval **cookie_val; + + FOREACH_KEYVAL(pos, val, cookie_key, cookie_val) { + zval *zv = php_http_ztyp(IS_STRING, *cookie_val); + + php_http_array_hashkey_stringify(&cookie_key); + php_http_buffer_appendf(&curl->options.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(zv)); + php_http_array_hashkey_stringfree(&cookie_key); + + zval_ptr_dtor(&zv); + } + + php_http_buffer_fix(&curl->options.cookies); + if (curl->options.cookies.used) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) { + return FAILURE; + } + } + } + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_encodecookies(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + + curl->options.encode_cookies = Z_BVAL_P(val); + return SUCCESS; +} + +static STATUS php_http_curle_option_set_lastmodified(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (Z_LVAL_P(val)) { + if (Z_LVAL_P(val) > 0) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, Z_LVAL_P(val))) { + return FAILURE; + } + } else { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, (long) PHP_HTTP_G->env.request.time + Z_LVAL_P(val))) { + return FAILURE; + } + } + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, (long) (curl->options.range_request ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE))) { + return FAILURE; + } + } else { + if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, 0) + || CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, 0) + ) { + return FAILURE; + } + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_compress(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + + if (Z_BVAL_P(val)) { + curl->options.headers = curl_slist_append(curl->options.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5"); + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_etag(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + php_http_buffer_t header; + zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"')); + + php_http_buffer_init(&header); + php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val)); + php_http_buffer_fix(&header); + curl->options.headers = curl_slist_append(curl->options.headers, header.data); + php_http_buffer_dtor(&header); + return SUCCESS; +} + +static STATUS php_http_curle_option_set_range(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + php_http_buffer_reset(&curl->options.ranges); + + if (val && Z_TYPE_P(val) != IS_NULL) { + HashPosition pos; + zval **rr, **rb, **re; + + FOREACH_VAL(pos, val, rr) { + if (Z_TYPE_PP(rr) == IS_ARRAY) { + if (2 == php_http_array_list(Z_ARRVAL_PP(rr) TSRMLS_CC, 2, &rb, &re)) { + if ( ((Z_TYPE_PP(rb) == IS_LONG) || ((Z_TYPE_PP(rb) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(rb), Z_STRLEN_PP(rb), NULL, NULL, 1))) && + ((Z_TYPE_PP(re) == IS_LONG) || ((Z_TYPE_PP(re) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(re), Z_STRLEN_PP(re), NULL, NULL, 1)))) { + zval *rbl = php_http_ztyp(IS_LONG, *rb); + zval *rel = php_http_ztyp(IS_LONG, *re); + + if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) { + php_http_buffer_appendf(&curl->options.ranges, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel)); + } + zval_ptr_dtor(&rbl); + zval_ptr_dtor(&rel); + } + + } + } + } + + if (curl->options.ranges.used) { + curl->options.range_request = 1; + /* ditch last comma */ + curl->options.ranges.data[curl->options.ranges.used - 1] = '\0'; + } + } + + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RANGE, curl->options.ranges.data)) { + return FAILURE; + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_resume(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + + if (Z_LVAL_P(val) > 0) { + curl->options.range_request = 1; + } + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESUME_FROM, Z_LVAL_P(val))) { + return FAILURE; + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_retrydelay(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + + curl->options.retry.delay = Z_DVAL_P(val); + return SUCCESS; +} + +static STATUS php_http_curle_option_set_retrycount(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + + curl->options.retry.count = Z_LVAL_P(val); + return SUCCESS; +} + +static STATUS php_http_curle_option_set_redirect(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + + if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_FOLLOWLOCATION, Z_LVAL_P(val) ? 1L : 0L) + || CURLE_OK != curl_easy_setopt(ch, CURLOPT_MAXREDIRS, curl->options.redirects = Z_LVAL_P(val)) + ) { + return FAILURE; + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_portrange(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + long localport = 0, localportrange = 0; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (val && Z_TYPE_P(val) != IS_NULL) { + zval **z_port_start, *zps_copy = NULL, **z_port_end, *zpe_copy = NULL; + + switch (php_http_array_list(Z_ARRVAL_P(val) TSRMLS_CC, 2, &z_port_start, &z_port_end)) { + case 2: + zps_copy = php_http_ztyp(IS_LONG, *z_port_start); + zpe_copy = php_http_ztyp(IS_LONG, *z_port_end); + localportrange = labs(Z_LVAL_P(zps_copy)-Z_LVAL_P(zpe_copy))+1L; + /* no break */ + case 1: + if (!zps_copy) { + zps_copy = php_http_ztyp(IS_LONG, *z_port_start); + } + localport = (zpe_copy && Z_LVAL_P(zpe_copy) > 0) ? MIN(Z_LVAL_P(zps_copy), Z_LVAL_P(zpe_copy)) : Z_LVAL_P(zps_copy); + zval_ptr_dtor(&zps_copy); + if (zpe_copy) { + zval_ptr_dtor(&zpe_copy); + } + break; + default: + break; + } + } + if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORT, localport) + || CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORTRANGE, localportrange) + ) { + return FAILURE; + } + return SUCCESS; +} + +#if PHP_HTTP_CURL_VERSION(7,21,3) +static STATUS php_http_curle_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (val && Z_TYPE_P(val) != IS_NULL) { + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + HashPosition pos; + zval **data; + + FOREACH_KEYVAL(pos, val, key, data) { + zval *cpy = php_http_ztyp(IS_STRING, *data); + curl->options.resolve = curl_slist_append(curl->options.resolve, Z_STRVAL_P(cpy)); + zval_ptr_dtor(&cpy); + } + + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, curl->options.resolve)) { + return FAILURE; + } + } else { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, NULL)) { + return FAILURE; + } + } + return SUCCESS; +} +#endif + +static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) +{ + php_http_option_t *opt; + + /* proxy */ + if ((opt = php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + php_http_option_register(registry, ZEND_STRL("proxytype"), CURLOPT_PROXYTYPE, IS_LONG); + php_http_option_register(registry, ZEND_STRL("proxyport"), CURLOPT_PROXYPORT, IS_LONG); + if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauth"), CURLOPT_PROXYUSERPWD, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauthtype"), CURLOPT_PROXYAUTH, IS_LONG))) { + Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE; + } + php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, IS_BOOL); +#if PHP_HTTP_CURL_VERSION(7,19,4) + php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING); +#endif + + /* dns */ + if ((opt = php_http_option_register(registry, ZEND_STRL("dns_cache_timeout"), CURLOPT_DNS_CACHE_TIMEOUT, IS_LONG))) { + Z_LVAL(opt->defval) = 60; + } + php_http_option_register(registry, ZEND_STRL("ipresolve"), CURLOPT_IPRESOLVE, IS_LONG); +#if PHP_HTTP_CURL_VERSION(7,21,3) + if ((opt = php_http_option_register(registry, ZEND_STRL("resolve"), CURLOPT_RESOLVE, IS_ARRAY))) { + opt->setter = php_http_curle_option_set_resolve; + } +#endif +#if PHP_HTTP_CURL_VERSION(7,24,0) + if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } +#endif + + /* limits */ + php_http_option_register(registry, ZEND_STRL("low_speed_limit"), CURLOPT_LOW_SPEED_LIMIT, IS_LONG); + php_http_option_register(registry, ZEND_STRL("low_speed_time"), CURLOPT_LOW_SPEED_TIME, IS_LONG); + + /* LSF weirdance + php_http_option_register(registry, ZEND_STRL("max_send_speed"), CURLOPT_MAX_SEND_SPEED_LARGE, IS_LONG); + php_http_option_register(registry, ZEND_STRL("max_recv_speed"), CURLOPT_MAX_RECV_SPEED_LARGE, IS_LONG); + */ + + /* connection handling */ + /* crashes + if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLOPT_MAXCONNECTS, IS_LONG))) { + Z_LVAL(opt->defval) = 5; + } + */ + php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, IS_BOOL); + + /* outgoing interface */ + php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING); + if ((opt = php_http_option_register(registry, ZEND_STRL("portrange"), CURLOPT_LOCALPORT, IS_ARRAY))) { + opt->setter = php_http_curle_option_set_portrange; + } + + /* another endpoint port */ + php_http_option_register(registry, ZEND_STRL("port"), CURLOPT_PORT, IS_LONG); + + /* RFC4007 zone_id */ +#if PHP_HTTP_CURL_VERSION(7,19,0) + php_http_option_register(registry, ZEND_STRL("address_scope"), CURLOPT_ADDRESS_SCOPE, IS_LONG); +#endif + + /* auth */ + if ((opt = php_http_option_register(registry, ZEND_STRL("httpauth"), CURLOPT_USERPWD, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG))) { + Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE; + } + + /* redirects */ + if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) { + opt->setter = php_http_curle_option_set_redirect; + } + php_http_option_register(registry, ZEND_STRL("unrestricted_auth"), CURLOPT_UNRESTRICTED_AUTH, IS_BOOL); +#if PHP_HTTP_CURL_VERSION(7,19,1) + php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POSTREDIR, IS_LONG); +#endif + + /* retries */ + if ((opt = php_http_option_register(registry, ZEND_STRL("retrycount"), 0, IS_LONG))) { + opt->setter = php_http_curle_option_set_retrycount; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("retrydelay"), 0, IS_DOUBLE))) { + opt->setter = php_http_curle_option_set_retrydelay; + } + + /* referer */ + if ((opt = php_http_option_register(registry, ZEND_STRL("referer"), CURLOPT_REFERER, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, IS_BOOL))) { + ZVAL_BOOL(&opt->defval, 1); + } + + /* useragent */ + if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) { + /* don't check strlen, to allow sending no useragent at all */ + ZVAL_STRING(&opt->defval, "PECL::HTTP/" PHP_HTTP_EXT_VERSION " (PHP/" PHP_VERSION ")", 0); + } + + /* resume */ + if ((opt = php_http_option_register(registry, ZEND_STRL("resume"), CURLOPT_RESUME_FROM, IS_LONG))) { + opt->setter = php_http_curle_option_set_resume; + } + /* ranges */ + if ((opt = php_http_option_register(registry, ZEND_STRL("range"), CURLOPT_RANGE, IS_ARRAY))) { + opt->setter = php_http_curle_option_set_range; + } + + /* etag */ + if ((opt = php_http_option_register(registry, ZEND_STRL("etag"), 0, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->setter = php_http_curle_option_set_etag; + } + + /* compression */ + if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, IS_BOOL))) { + opt->setter = php_http_curle_option_set_compress; + } + + /* lastmodified */ + if ((opt = php_http_option_register(registry, ZEND_STRL("lastmodified"), 0, IS_LONG))) { + opt->setter = php_http_curle_option_set_lastmodified; + } + + /* cookies */ + if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, IS_BOOL))) { + opt->setter = php_http_curle_option_set_encodecookies; + ZVAL_BOOL(&opt->defval, 1); + } + if ((opt = php_http_option_register(registry, ZEND_STRL("cookies"), 0, IS_ARRAY))) { + opt->setter = php_http_curle_option_set_cookies; + } + + /* cookiesession, don't load session cookies from cookiestore */ + php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, IS_BOOL); + /* cookiestore, read initial cookies from that file and store cookies back into that file */ + if ((opt = php_http_option_register(registry, ZEND_STRL("cookiestore"), 0, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + opt->setter = php_http_curle_option_set_cookiestore; + } + + /* maxfilesize */ + php_http_option_register(registry, ZEND_STRL("maxfilesize"), CURLOPT_MAXFILESIZE, IS_LONG); + + /* http protocol version */ + php_http_option_register(registry, ZEND_STRL("protocol"), CURLOPT_HTTP_VERSION, IS_LONG); + + /* timeouts */ + if ((opt = php_http_option_register(registry, ZEND_STRL("timeout"), CURLOPT_TIMEOUT_MS, IS_DOUBLE))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("connecttimeout"), CURLOPT_CONNECTTIMEOUT_MS, IS_DOUBLE))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS; + Z_DVAL(opt->defval) = 3; + } + + /* tcp */ +#if PHP_HTTP_CURL_VERSION(7,25,0) + php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, IS_BOOL); + if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) { + Z_LVAL(opt->defval) = 60; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepintvl"), CURLOPT_TCP_KEEPINTVL, IS_LONG))) { + Z_LVAL(opt->defval) = 60; + } +#endif + + /* ssl */ + if ((opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) { + registry = &opt->suboptions; + + if ((opt = php_http_option_register(registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } + php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING); + + if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } + php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING); + php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING); + php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING); + php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG); + if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, IS_BOOL))) { + ZVAL_BOOL(&opt->defval, 1); + } + if ((opt = php_http_option_register(registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, IS_BOOL))) { + ZVAL_BOOL(&opt->defval, 1); + opt->setter = php_http_curle_option_set_ssl_verifyhost; + } + php_http_option_register(registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING); + if ((opt = php_http_option_register(registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; +#ifdef PHP_HTTP_CURL_CAINFO + ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAINFO, 0); +#endif + } + if ((opt = php_http_option_register(registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } +#if PHP_HTTP_CURL_VERSION(7,19,0) + if ((opt = php_http_option_register(registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } +# ifdef PHP_HTTP_HAVE_OPENSSL + if ((opt = php_http_option_register(registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } +# endif +#endif +#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL) + php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL); +#endif + } +} + +static zval *php_http_curle_get_option(php_http_option_t *opt, HashTable *options, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + zval *option; + + if ((option = php_http_option_get(opt, options, NULL))) { + option = php_http_ztyp(opt->type, option); + zend_hash_quick_update(&curl->options.cache, opt->name.s, opt->name.l, opt->name.h, &option, sizeof(zval *), NULL); + } + return option; +} + +static STATUS php_http_curle_set_option(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + zval tmp; + STATUS rv = SUCCESS; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (!val) { + val = &opt->defval; + } + + switch (opt->type) { + case IS_BOOL: + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_BVAL_P(val))) { + rv = FAILURE; + } + break; + + case IS_LONG: + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_LVAL_P(val))) { + rv = FAILURE; + } + break; + + case IS_STRING: + if (!(opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_STRLEN) || Z_STRLEN_P(val)) { + if (!(opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR) || !Z_STRVAL_P(val) || SUCCESS == php_check_open_basedir(Z_STRVAL_P(val) TSRMLS_CC)) { + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val))) { + rv = FAILURE; + } + } + } + break; + + case IS_DOUBLE: + if (opt->flags & PHP_HTTP_CURLE_OPTION_TRANSFORM_MS) { + tmp = *val; + Z_DVAL(tmp) *= 1000; + val = &tmp; + } + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_DVAL_P(val))) { + rv = FAILURE; + } + break; + + case IS_ARRAY: + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (Z_TYPE_P(val) != IS_NULL) { + rv = php_http_options_apply(&opt->suboptions, Z_ARRVAL_P(val), curl); + } + break; + + default: + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else { + rv = FAILURE; + } + break; + } + if (rv != SUCCESS) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s", opt->name.s); + } + return rv; +} + + +/* client ops */ + +static STATUS php_http_client_curl_handler_reset(php_http_client_curl_handler_t *curl) +{ + CURL *ch = curl->handle; + php_http_curle_storage_t *st; + + if ((st = php_http_curle_get_storage(ch))) { + if (st->url) { + pefree(st->url, 1); + st->url = NULL; + } + if (st->cookiestore) { + pefree(st->cookiestore, 1); + st->cookiestore = NULL; + } + st->errorbuffer[0] = '\0'; + } + + curl_easy_setopt(ch, CURLOPT_URL, NULL); + /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */ +#if PHP_HTTP_CURL_VERSION(7,19,1) + curl_easy_setopt(ch, CURLOPT_PROXYUSERNAME, NULL); + curl_easy_setopt(ch, CURLOPT_PROXYPASSWORD, NULL); + curl_easy_setopt(ch, CURLOPT_USERNAME, NULL); + curl_easy_setopt(ch, CURLOPT_PASSWORD, NULL); +#endif + +#if PHP_HTTP_CURL_VERSION(7,21,3) + if (curl->options.resolve) { + curl_slist_free_all(curl->options.resolve); + curl->options.resolve = NULL; + } +#endif + curl->options.retry.count = 0; + curl->options.retry.delay = 0; + curl->options.redirects = 0; + curl->options.encode_cookies = 1; + + if (curl->options.headers) { + curl_slist_free_all(curl->options.headers); + curl->options.headers = NULL; + } + + php_http_buffer_reset(&curl->options.cookies); + php_http_buffer_reset(&curl->options.ranges); + + return SUCCESS; +} + +static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_http_client_t *h, php_resource_factory_t *rf) +{ + void *handle; + php_http_client_curl_handler_t *handler; + TSRMLS_FETCH_FROM_CTX(h->ts); + + if (!(handle = php_resource_factory_handle_ctor(rf, NULL TSRMLS_CC))) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize curl handle"); + return NULL; + } + + handler = ecalloc(1, sizeof(*handler)); + handler->rf = rf; + handler->client = h; + handler->handle = handle; + handler->request.buffer = php_http_buffer_init(NULL); + handler->request.parser = php_http_message_parser_init(NULL TSRMLS_CC); + handler->request.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); + handler->response.buffer = php_http_buffer_init(NULL); + handler->response.parser = php_http_message_parser_init(NULL TSRMLS_CC); + handler->response.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); + php_http_buffer_init(&handler->options.cookies); + php_http_buffer_init(&handler->options.ranges); + zend_hash_init(&handler->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0); + +#if defined(ZTS) + curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L); +#endif + curl_easy_setopt(handle, CURLOPT_HEADER, 0L); + curl_easy_setopt(handle, CURLOPT_FILETIME, 1L); + curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L); + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, NULL); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, php_http_curle_dummy_callback); + curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, php_http_curle_raw_callback); + curl_easy_setopt(handle, CURLOPT_READFUNCTION, php_http_curle_read_callback); + curl_easy_setopt(handle, CURLOPT_IOCTLFUNCTION, php_http_curle_ioctl_callback); + curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback); + curl_easy_setopt(handle, CURLOPT_DEBUGDATA, handler); + curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, handler); + + php_http_client_curl_handler_reset(handler); + + return handler; +} + + +static STATUS php_http_client_curl_handler_prepare(php_http_client_curl_handler_t *curl, php_http_client_enqueue_t *enqueue) +{ + size_t body_size; + php_http_message_t *msg = enqueue->request; + php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle); + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + /* request url */ + if (!PHP_HTTP_INFO(msg).request.url) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot request empty URL"); + return FAILURE; + } + storage->errorbuffer[0] = '\0'; + if (storage->url) { + pefree(storage->url, 1); + } + storage->url = pestrdup(PHP_HTTP_INFO(msg).request.url, 1); + curl_easy_setopt(curl->handle, CURLOPT_URL, storage->url); + + /* request method */ + switch (php_http_select_str(PHP_HTTP_INFO(msg).request.method, 4, "GET", "HEAD", "POST", "PUT")) { + case 0: + curl_easy_setopt(curl->handle, CURLOPT_HTTPGET, 1L); + break; + + case 1: + curl_easy_setopt(curl->handle, CURLOPT_NOBODY, 1L); + break; + + case 2: + curl_easy_setopt(curl->handle, CURLOPT_POST, 1L); + break; + + case 3: + curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L); + break; + + default: { + if (PHP_HTTP_INFO(msg).request.method) { + curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot use empty request method"); + return FAILURE; + } + break; + } + } + + /* request headers */ + php_http_message_update_headers(msg); + if (zend_hash_num_elements(&msg->hdrs)) { + php_http_array_hashkey_t header_key = php_http_array_hashkey_init(0); + zval **header_val; + HashPosition pos; + php_http_buffer_t header; + + php_http_buffer_init(&header); + FOREACH_HASH_KEYVAL(pos, &msg->hdrs, header_key, header_val) { + if (header_key.type == HASH_KEY_IS_STRING) { + zval *header_cpy = php_http_ztyp(IS_STRING, *header_val); + + php_http_buffer_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy)); + php_http_buffer_fix(&header); + curl->options.headers = curl_slist_append(curl->options.headers, header.data); + php_http_buffer_reset(&header); + + zval_ptr_dtor(&header_cpy); + } + } + php_http_buffer_dtor(&header); + curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers); + } + + /* attach request body */ + if ((body_size = php_http_message_body_size(msg->body))) { + /* RFC2616, section 4.3 (para. 4) states that »a message-body MUST NOT be included in a request if the + * specification of the request method (section 5.1.1) does not allow sending an entity-body in request.« + * Following the clause in section 5.1.1 (para. 2) that request methods »MUST be implemented with the + * same semantics as those specified in section 9« reveal that not any single defined HTTP/1.1 method + * does not allow a request body. + */ + php_stream_rewind(php_http_message_body_stream(msg->body)); + curl_easy_setopt(curl->handle, CURLOPT_IOCTLDATA, msg->body); + curl_easy_setopt(curl->handle, CURLOPT_READDATA, msg->body); + curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, body_size); + curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, body_size); + } + + php_http_options_apply(&php_http_curle_options, enqueue->options, curl); + + return SUCCESS; +} + +static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *handler) +{ + TSRMLS_FETCH_FROM_CTX(handler->client->ts); + + curl_easy_setopt(handler->handle, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(handler->handle, CURLOPT_PROGRESSFUNCTION, NULL); + curl_easy_setopt(handler->handle, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(handler->handle, CURLOPT_DEBUGFUNCTION, NULL); + + php_resource_factory_handle_dtor(handler->rf, handler->handle TSRMLS_CC); + php_resource_factory_free(&handler->rf); + + php_http_message_parser_free(&handler->request.parser); + php_http_message_free(&handler->request.message); + php_http_buffer_free(&handler->request.buffer); + php_http_message_parser_free(&handler->response.parser); + php_http_message_free(&handler->response.message); + php_http_buffer_free(&handler->response.buffer); + php_http_buffer_dtor(&handler->options.ranges); + php_http_buffer_dtor(&handler->options.cookies); + zend_hash_destroy(&handler->options.cache); + + if (handler->options.headers) { + curl_slist_free_all(handler->options.headers); + handler->options.headers = NULL; + } + + efree(handler); +} + +static php_http_client_t *php_http_client_curl_init(php_http_client_t *h, void *handle) +{ + php_http_client_curl_t *curl; + TSRMLS_FETCH_FROM_CTX(h->ts); + + if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL TSRMLS_CC))) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize curl handle"); + return NULL; + } + + curl = ecalloc(1, sizeof(*curl)); + curl->handle = handle; + curl->unfinished = 0; + h->ctx = curl; + + return h; +} + +static void php_http_client_curl_dtor(php_http_client_t *h) +{ + php_http_client_curl_t *curl = h->ctx; + TSRMLS_FETCH_FROM_CTX(h->ts); + +#if PHP_HTTP_HAVE_EVENT + if (curl->timeout) { + efree(curl->timeout); + curl->timeout = NULL; + } +#endif + curl->unfinished = 0; + + php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC); + + efree(curl); + h->ctx = NULL; +} + +static void queue_dtor(php_http_client_enqueue_t *e) +{ + php_http_client_curl_handler_t *handler = e->opaque; + + if (handler->queue.dtor) { + e->opaque = handler->queue.opaque; + handler->queue.dtor(e); + } + php_http_client_curl_handler_dtor(handler); +} + +static php_resource_factory_t *create_rf(const char *url TSRMLS_DC) +{ + php_url *purl; + php_resource_factory_t *rf = NULL; + + if (!url || !*url) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot request empty URL"); + return NULL; + } + + purl = php_url_parse(url); + + if (!purl) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse URL '%s'", url); + return NULL; + } else { + char *id_str = NULL; + size_t id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(purl->host), purl->port ? purl->port : 80); + php_persistent_handle_factory_t *pf = php_persistent_handle_concede(NULL, ZEND_STRL("http\\Client\\Curl\\Request"), id_str, id_len, NULL, NULL TSRMLS_CC); + + if (pf) { + rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void*)) php_persistent_handle_abandon); + } + + php_url_free(purl); + efree(id_str); + } + + if (!rf) { + rf = php_resource_factory_init(NULL, &php_http_curle_resource_factory_ops, NULL, NULL); + } + + return rf; +} + +static STATUS php_http_client_curl_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) +{ + CURLMcode rs; + php_http_client_curl_t *curl = h->ctx; + php_http_client_curl_handler_t *handler; + php_http_client_progress_state_t *progress; + php_resource_factory_t *rf; + TSRMLS_FETCH_FROM_CTX(h->ts); + + rf = create_rf(enqueue->request->http.info.request.url TSRMLS_CC); + if (!rf) { + return FAILURE; + } + + handler = php_http_client_curl_handler_init(h, rf); + if (!handler) { + return FAILURE; + } + + if (SUCCESS != php_http_client_curl_handler_prepare(handler, enqueue)) { + php_http_client_curl_handler_dtor(handler); + return FAILURE; + } + + handler->queue = *enqueue; + enqueue->opaque = handler; + enqueue->dtor = queue_dtor; + + if (CURLM_OK == (rs = curl_multi_add_handle(curl->handle, handler->handle))) { + zend_llist_add_element(&h->requests, enqueue); + ++curl->unfinished; + + if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) { + progress->info = "start"; + h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress); + progress->started = 1; + } + + return SUCCESS; + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs)); + return FAILURE; + } +} + +static STATUS php_http_client_curl_dequeue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) +{ + CURLMcode rs; + php_http_client_curl_t *curl = h->ctx; + php_http_client_curl_handler_t *handler = enqueue->opaque; + TSRMLS_FETCH_FROM_CTX(h->ts); + + if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle, handler->handle))) { + zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue); + return SUCCESS; + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not dequeue request: %s", curl_multi_strerror(rs)); + } + + return FAILURE; +} + +static void php_http_client_curl_reset(php_http_client_t *h) +{ + zend_llist_element *next_el, *this_el; + + for (this_el = h->requests.head; this_el; this_el = next_el) { + next_el = this_el->next; + php_http_client_curl_dequeue(h, (void *) this_el->data); + } +} + +#ifdef PHP_WIN32 +# define SELECT_ERROR SOCKET_ERROR +#else +# define SELECT_ERROR -1 +#endif + +static STATUS php_http_client_curl_wait(php_http_client_t *h, struct timeval *custom_timeout) +{ + int MAX; + fd_set R, W, E; + struct timeval timeout; + php_http_client_curl_t *curl = h->ctx; + +#if PHP_HTTP_HAVE_EVENT + if (curl->useevents) { + TSRMLS_FETCH_FROM_CTX(h->ts); + + php_error_docref(NULL TSRMLS_CC, E_WARNING, "not implemented"); + return FAILURE; + } +#endif + + FD_ZERO(&R); + FD_ZERO(&W); + FD_ZERO(&E); + + if (CURLM_OK == curl_multi_fdset(curl->handle, &R, &W, &E, &MAX)) { + if (custom_timeout && timerisset(custom_timeout)) { + timeout = *custom_timeout; + } else { + long max_tout = 1000; + + if ((CURLM_OK == curl_multi_timeout(curl->handle, &max_tout)) && (max_tout > 0)) { + timeout.tv_sec = max_tout / 1000; + timeout.tv_usec = (max_tout % 1000) * 1000; + } else { + timeout.tv_sec = 0; + timeout.tv_usec = 1000; + } + } + + if (MAX == -1) { + php_http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / PHP_HTTP_MCROSEC)); + return SUCCESS; + } else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) { + return SUCCESS; + } + } + return FAILURE; +} + +static int php_http_client_curl_once(php_http_client_t *h) +{ + php_http_client_curl_t *curl = h->ctx; + +#if PHP_HTTP_HAVE_EVENT + if (curl->useevents) { + TSRMLS_FETCH_FROM_CTX(h->ts); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "not implemented"); + return FAILURE; + } +#endif + + while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle, &curl->unfinished)); + + php_http_curlm_responsehandler(h); + + return curl->unfinished; + +} + +static STATUS php_http_client_curl_exec(php_http_client_t *h) +{ + TSRMLS_FETCH_FROM_CTX(h->ts); + +#if PHP_HTTP_HAVE_EVENT + php_http_client_curl_t *curl = h->ctx; + + if (curl->useevents) { + php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h); + do { + int ev_rc = event_base_dispatch(PHP_HTTP_G->curl.event_base); + +#if DBG_EVENTS + fprintf(stderr, "%c", "X.0"[ev_rc+1]); +#endif + + if (ev_rc < 0) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error in event_base_dispatch()"); + return FAILURE; + } + } while (curl->unfinished); + } else +#endif + { + while (php_http_client_curl_once(h)) { + if (SUCCESS != php_http_client_curl_wait(h, NULL)) { +#ifdef PHP_WIN32 + /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "WinSock error: %d", WSAGetLastError()); +#else + php_error_docref(NULL TSRMLS_CC, E_WARNING, strerror(errno)); +#endif + return FAILURE; + } + } + } + + return SUCCESS; +} + +static STATUS php_http_client_curl_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg) +{ + php_http_client_curl_t *curl = h->ctx; + + switch (opt) { + case PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING: + if (CURLM_OK != curl_multi_setopt(curl->handle, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) { + return FAILURE; + } + break; + + case PHP_HTTP_CLIENT_OPT_USE_EVENTS: +#if PHP_HTTP_HAVE_EVENT + if ((curl->useevents = *((zend_bool *) arg))) { + if (!curl->timeout) { + curl->timeout = ecalloc(1, sizeof(struct event)); + } + curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, h); + curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, php_http_curlm_socket_callback); + curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, h); + curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, php_http_curlm_timer_callback); + } else { + curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, NULL); + curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, NULL); + curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, NULL); + curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, NULL); + } + break; +#endif + + default: + return FAILURE; + } + return SUCCESS; +} + +static STATUS php_http_client_curl_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void **res) +{ + php_http_client_enqueue_t *enqueue; + + switch (opt) { + case PHP_HTTP_CLIENT_OPT_PROGRESS_INFO: + if ((enqueue = php_http_client_enqueued(h, arg, NULL))) { + php_http_client_curl_handler_t *handler = enqueue->opaque; + + *((php_http_client_progress_state_t **) res) = &handler->progress; + return SUCCESS; + } + break; + + case PHP_HTTP_CLIENT_OPT_TRANSFER_INFO: + if ((enqueue = php_http_client_enqueued(h, arg, NULL))) { + php_http_client_curl_handler_t *handler = enqueue->opaque; + + php_http_curle_get_info(handler->handle, *(HashTable **) res); + return SUCCESS; + } + break; + + default: + break; + } + + return FAILURE; +} + +static php_http_client_ops_t php_http_client_curl_ops = { + &php_http_curlm_resource_factory_ops, + php_http_client_curl_init, + NULL /* copy */, + php_http_client_curl_dtor, + php_http_client_curl_reset, + php_http_client_curl_exec, + php_http_client_curl_wait, + php_http_client_curl_once, + php_http_client_curl_enqueue, + php_http_client_curl_dequeue, + php_http_client_curl_setopt, + php_http_client_curl_getopt +}; + +php_http_client_ops_t *php_http_client_curl_get_ops(void) +{ + return &php_http_client_curl_ops; +} + +PHP_MINIT_FUNCTION(http_client_curl) +{ + php_http_options_t *options; + php_http_client_driver_t driver = { + ZEND_STRL("curl"), + &php_http_client_curl_ops + }; + + if (SUCCESS != php_http_client_driver_add(&driver)) { + return FAILURE; + } + + if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http\\Client\\Curl"), &php_http_curlm_resource_factory_ops, NULL, NULL TSRMLS_CC)) { + return FAILURE; + } + if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http\\Client\\Curl\\Request"), &php_http_curle_resource_factory_ops, NULL, NULL TSRMLS_CC)) { + return FAILURE; + } + + if ((options = php_http_options_init(&php_http_curle_options, 1))) { + options->getter = php_http_curle_get_option; + options->setter = php_http_curle_set_option; + + php_http_curle_options_init(options TSRMLS_CC); + } + + /* + * HTTP Protocol Version Constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_0", CURL_HTTP_VERSION_1_0, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE, CONST_CS|CONST_PERSISTENT); + + /* + * SSL Version Constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1", CURL_SSLVERSION_TLSv1, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT, CONST_CS|CONST_PERSISTENT); + + /* + * DNS IPvX resolving + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V4", CURL_IPRESOLVE_V4, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V6", CURL_IPRESOLVE_V6, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_ANY", CURL_IPRESOLVE_WHATEVER, CONST_CS|CONST_PERSISTENT); + + /* + * Auth Constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_BASIC", CURLAUTH_BASIC, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST", CURLAUTH_DIGEST, CONST_CS|CONST_PERSISTENT); +#if PHP_HTTP_CURL_VERSION(7,19,3) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST_IE", CURLAUTH_DIGEST_IE, CONST_CS|CONST_PERSISTENT); +#endif + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_NTLM", CURLAUTH_NTLM, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_ANY", CURLAUTH_ANY, CONST_CS|CONST_PERSISTENT); + + /* + * Proxy Type Constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4", CURLPROXY_SOCKS4, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4A", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5_HOSTNAME", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP", CURLPROXY_HTTP, CONST_CS|CONST_PERSISTENT); +# if PHP_HTTP_CURL_VERSION(7,19,4) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP_1_0", CURLPROXY_HTTP_1_0, CONST_CS|CONST_PERSISTENT); +# endif + + /* + * Post Redirection Constants + */ +#if PHP_HTTP_CURL_VERSION(7,19,1) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_301", CURL_REDIR_POST_301, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_302", CURL_REDIR_POST_302, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_ALL", CURL_REDIR_POST_ALL, CONST_CS|CONST_PERSISTENT); +#endif + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(http_client_curl) +{ + php_http_options_dtor(&php_http_curle_options); + return SUCCESS; +} + +#if PHP_HTTP_HAVE_EVENT +PHP_RINIT_FUNCTION(http_client_curl) +{ + if (!PHP_HTTP_G->curl.event_base && !(PHP_HTTP_G->curl.event_base = event_base_new())) { + return FAILURE; + } + return SUCCESS; +} +PHP_RSHUTDOWN_FUNCTION(http_client_curl) +{ + if (PHP_HTTP_G->curl.event_base) { + event_base_free(PHP_HTTP_G->curl.event_base); + PHP_HTTP_G->curl.event_base = NULL; + } + return SUCCESS; +} +#endif /* PHP_HTTP_HAVE_EVENT */ + +#endif /* PHP_HTTP_HAVE_CURL */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_client_curl.h b/php_http_client_curl.h new file mode 100644 index 0000000..6495568 --- /dev/null +++ b/php_http_client_curl.h @@ -0,0 +1,40 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_CLIENT_CURL_H +#define PHP_HTTP_CLIENT_CURL_H + +#if PHP_HTTP_HAVE_CURL + +#if PHP_HTTP_HAVE_EVENT +struct php_http_curl_globals { + void *event_base; +}; + +PHP_RINIT_FUNCTION(http_client_curl); +PHP_RSHUTDOWN_FUNCTION(http_client_curl); +#endif /* PHP_HTTP_HAVE_EVENT */ + +PHP_MINIT_FUNCTION(http_client_curl); +PHP_MSHUTDOWN_FUNCTION(http_client_curl); +#endif /* PHP_HTTP_HAVE_CURL */ + +#endif /* PHP_HTTP_CLIENT_CURL_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_client_request.c b/php_http_client_request.c new file mode 100644 index 0000000..12f2014 --- /dev/null +++ b/php_http_client_request.c @@ -0,0 +1,323 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite TSRMLS_DC); +void php_http_client_options_set(zval *this_ptr, zval *opts TSRMLS_DC); +void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value TSRMLS_DC); + +#define PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj) \ + do { \ + if (!obj->message) { \ + obj->message = php_http_message_init(NULL, PHP_HTTP_REQUEST, NULL TSRMLS_CC); \ + } \ + } while(0) + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest___construct, 0, 0, 0) + ZEND_ARG_INFO(0, method) + ZEND_ARG_INFO(0, url) + ZEND_ARG_ARRAY_INFO(0, headers, 1) + ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, __construct) +{ + char *meth_str = NULL, *url_str = NULL; + int meth_len = 0, url_len = 0; + zval *zheaders = NULL, *zbody = NULL; + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!a!O!", &meth_str, &meth_len, &url_str, &url_len, &zheaders, &zbody, php_http_message_body_class_entry), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (obj->message) { + php_http_message_set_type(obj->message, PHP_HTTP_REQUEST); + } else { + obj->message = php_http_message_init(NULL, PHP_HTTP_REQUEST, NULL TSRMLS_CC); + } + + if (zbody) { + php_http_expect(SUCCESS == php_http_message_object_set_body(obj, zbody TSRMLS_CC), unexpected_val, return); + } + if (meth_str && meth_len) { + PHP_HTTP_INFO(obj->message).request.method = estrndup(meth_str, meth_len); + } + if (url_str && url_len) { + PHP_HTTP_INFO(obj->message).request.url = estrndup(url_str, url_len); + } + if (zheaders) { + array_copy(Z_ARRVAL_P(zheaders), &obj->message->hdrs); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setContentType, 0, 0, 1) + ZEND_ARG_INFO(0, content_type) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, setContentType) +{ + char *ct_str; + int ct_len; + php_http_message_object_t *obj; + zval *zct; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ct_str, &ct_len), invalid_arg, return); + + if (ct_len && !strchr(ct_str, '/')) { + php_http_throw(unexpected_val, "Content type \"%s\" does not seem to contain a primary and a secondary part", ct_str); + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); + + MAKE_STD_ZVAL(zct); + ZVAL_STRINGL(zct, ct_str, ct_len, 1); + zend_hash_update(&obj->message->hdrs, "Content-Type", sizeof("Content-Type"), (void *) &zct, sizeof(void *), NULL); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getContentType, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, getContentType) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zval *zct; + + PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); + + php_http_message_update_headers(obj->message); + zct = php_http_message_header(obj->message, ZEND_STRL("Content-Type"), 1); + if (zct) { + RETURN_ZVAL(zct, 0, 1); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setQuery, 0, 0, 0) + ZEND_ARG_INFO(0, query_data) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, setQuery) +{ + zval *qdata = NULL; + php_http_message_object_t *obj; + php_url *old_url = NULL, new_url = {NULL}; + char empty[] = ""; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!", &qdata), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); + + if (qdata) { + zval arr, str; + + INIT_PZVAL(&arr); + array_init(&arr); + INIT_PZVAL(&str); + ZVAL_NULL(&str); + + php_http_expect(SUCCESS == php_http_querystring_update(&arr, qdata, &str TSRMLS_CC), bad_querystring, + zval_dtor(&arr); + return; + ); + new_url.query = Z_STRVAL(str); + zval_dtor(&arr); + } else { + new_url.query = &empty[0]; + } + + if (obj->message->http.info.request.url) { + old_url = php_url_parse(obj->message->http.info.request.url); + efree(obj->message->http.info.request.url); + } + + php_http_url(PHP_HTTP_URL_REPLACE, old_url, &new_url, NULL, &obj->message->http.info.request.url, NULL TSRMLS_CC); + + if (old_url) { + php_url_free(old_url); + } + if (new_url.query != &empty[0]) { + STR_FREE(new_url.query); + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getQuery, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, getQuery) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); + + if (obj->message->http.info.request.url) { + php_url *purl = php_url_parse(obj->message->http.info.request.url); + + if (purl) { + if (purl->query) { + RETVAL_STRING(purl->query, 0); + purl->query = NULL; + } + php_url_free(purl); + } + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_addQuery, 0, 0, 1) + ZEND_ARG_INFO(0, query_data) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, addQuery) +{ + zval *qdata, arr, str; + php_http_message_object_t *obj; + php_url *old_url = NULL, new_url = {NULL}; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); + + INIT_PZVAL(&arr); + array_init(&arr); + INIT_PZVAL(&str); + ZVAL_NULL(&str); + + php_http_expect(SUCCESS == php_http_querystring_update(&arr, qdata, &str TSRMLS_CC), bad_querystring, + zval_dtor(&arr); + return; + ); + new_url.query = Z_STRVAL(str); + zval_dtor(&arr); + + if (obj->message->http.info.request.url) { + old_url = php_url_parse(obj->message->http.info.request.url); + efree(obj->message->http.info.request.url); + } + + php_http_url(PHP_HTTP_URL_JOIN_QUERY, old_url, &new_url, NULL, &obj->message->http.info.request.url, NULL TSRMLS_CC); + + if (old_url) { + php_url_free(old_url); + } + STR_FREE(new_url.query); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setOptions, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, options, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, setOptions) +{ + zval *opts = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return); + + php_http_client_options_set(getThis(), opts TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getOptions, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, getOptions) +{ + if (SUCCESS == zend_parse_parameters_none()) { + zval *zoptions = zend_read_property(php_http_client_request_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + RETURN_ZVAL(zoptions, 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setSslOptions, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, ssl_options, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, setSslOptions) +{ + zval *opts = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return); + + php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 1 TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_addSslOptions, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, ssl_options, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, addSslOptions) +{ + zval *opts = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return); + + php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 0 TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getSslOptions, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientRequest, getSslOptions) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_client_options_get_subr(getThis(), ZEND_STRS("ssl"), return_value TSRMLS_CC); + } +} + +static zend_function_entry php_http_client_request_methods[] = { + PHP_ME(HttpClientRequest, __construct, ai_HttpClientRequest___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpClientRequest, setContentType, ai_HttpClientRequest_setContentType, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientRequest, getContentType, ai_HttpClientRequest_getContentType, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientRequest, setQuery, ai_HttpClientRequest_setQuery, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientRequest, getQuery, ai_HttpClientRequest_getQuery, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientRequest, addQuery, ai_HttpClientRequest_addQuery, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientRequest, setOptions, ai_HttpClientRequest_setOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientRequest, getOptions, ai_HttpClientRequest_getOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientRequest, setSslOptions, ai_HttpClientRequest_setSslOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientRequest, getSslOptions, ai_HttpClientRequest_getSslOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientRequest, addSslOptions, ai_HttpClientRequest_addSslOptions, ZEND_ACC_PUBLIC) + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_client_request_class_entry; + +PHP_MINIT_FUNCTION(http_client_request) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http\\Client", "Request", php_http_client_request_methods); + php_http_client_request_class_entry = zend_register_internal_class_ex(&ce, php_http_message_class_entry, NULL TSRMLS_CC); + + zend_declare_property_null(php_http_client_request_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED TSRMLS_CC); + + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_client_request.h b/php_http_client_request.h new file mode 100644 index 0000000..5f4da53 --- /dev/null +++ b/php_http_client_request.h @@ -0,0 +1,28 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_CLIENT_REQUEST_H +#define PHP_HTTP_CLIENT_REQUEST_H + +PHP_HTTP_API zend_class_entry *php_http_client_request_class_entry; +PHP_MINIT_FUNCTION(http_client_request); + +#endif /* PHP_HTTP_CLIENT_REQUEST_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_client_response.c b/php_http_client_response.c new file mode 100644 index 0000000..b269caf --- /dev/null +++ b/php_http_client_response.c @@ -0,0 +1,143 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientResponse_getCookies, 0, 0, 0) + ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, allowed_extras) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientResponse, getCookies) +{ + long flags = 0; + zval *allowed_extras_array = NULL; + int i = 0; + char **allowed_extras = NULL; + zval *header = NULL, **entry = NULL; + HashPosition pos; + php_http_message_object_t *msg; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|la!", &flags, &allowed_extras_array)) { + return; + } + + msg = zend_object_store_get_object(getThis() TSRMLS_CC); + array_init(return_value); + + if (allowed_extras_array) { + allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *)); + FOREACH_VAL(pos, allowed_extras_array, entry) { + zval *data = php_http_ztyp(IS_STRING, *entry); + allowed_extras[i++] = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data)); + zval_ptr_dtor(&data); + } + } + + if ((header = php_http_message_header(msg->message, ZEND_STRL("Set-Cookie"), 0))) { + php_http_cookie_list_t *list; + + if (Z_TYPE_P(header) == IS_ARRAY) { + zval **single_header; + + FOREACH_VAL(pos, header, single_header) { + zval *data = php_http_ztyp(IS_STRING, *single_header); + + if ((list = php_http_cookie_list_parse(NULL, Z_STRVAL_P(data), Z_STRLEN_P(data), flags, allowed_extras TSRMLS_CC))) { + zval *cookie; + + MAKE_STD_ZVAL(cookie); + ZVAL_OBJVAL(cookie, php_http_cookie_object_new_ex(php_http_cookie_class_entry, list, NULL TSRMLS_CC), 0); + add_next_index_zval(return_value, cookie); + } + zval_ptr_dtor(&data); + } + } else { + zval *data = php_http_ztyp(IS_STRING, header); + if ((list = php_http_cookie_list_parse(NULL, Z_STRVAL_P(data), Z_STRLEN_P(data), flags, allowed_extras TSRMLS_CC))) { + zval *cookie; + + MAKE_STD_ZVAL(cookie); + ZVAL_OBJVAL(cookie, php_http_cookie_object_new_ex(php_http_cookie_class_entry, list, NULL TSRMLS_CC), 0); + add_next_index_zval(return_value, cookie); + } + zval_ptr_dtor(&data); + } + zval_ptr_dtor(&header); + } + + if (allowed_extras) { + for (i = 0; allowed_extras[i]; ++i) { + efree(allowed_extras[i]); + } + efree(allowed_extras); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientResponse_getTransferInfo, 0, 0, 0) + ZEND_ARG_INFO(0, element) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientResponse, getTransferInfo) +{ + char *info_name = NULL; + int info_len = 0; + zval *info; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len), invalid_arg, return); + + info = zend_read_property(php_http_client_response_class_entry, getThis(), ZEND_STRL("transferInfo"), 0 TSRMLS_CC); + + /* request completed? */ + if (Z_TYPE_P(info) != IS_OBJECT) { + php_http_throw(bad_method_call, "Incomplete state", NULL); + return; + } + + if (info_len && info_name) { + info = zend_read_property(NULL, info, php_http_pretty_key(info_name, info_len, 0, 0), info_len, 0 TSRMLS_CC); + + if (!info) { + php_http_throw(unexpected_val, "Could not find transfer info with name '%s'", info_name); + return; + } + } + + RETURN_ZVAL(info, 1, 0); +} + +static zend_function_entry php_http_client_response_methods[] = { + PHP_ME(HttpClientResponse, getCookies, ai_HttpClientResponse_getCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientResponse, getTransferInfo, ai_HttpClientResponse_getTransferInfo, ZEND_ACC_PUBLIC) + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_client_response_class_entry; + +PHP_MINIT_FUNCTION(http_client_response) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http\\Client", "Response", php_http_client_response_methods); + php_http_client_response_class_entry = zend_register_internal_class_ex(&ce, php_http_message_class_entry, NULL TSRMLS_CC); + zend_declare_property_null(php_http_client_response_class_entry, ZEND_STRL("transferInfo"), ZEND_ACC_PROTECTED TSRMLS_CC); + + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_client_response.h b/php_http_client_response.h new file mode 100644 index 0000000..6cf677a --- /dev/null +++ b/php_http_client_response.h @@ -0,0 +1,29 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_CLIENT_RESPONSE_H +#define PHP_HTTP_CLIENT_RESPONSE_H + +PHP_HTTP_API zend_class_entry *php_http_client_response_class_entry; +PHP_MINIT_FUNCTION(http_client_response); + +#endif /* PHP_HTTP_CLIENT_RESPONSE_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_cookie.c b/php_http_cookie.c new file mode 100644 index 0000000..1234e38 --- /dev/null +++ b/php_http_cookie.c @@ -0,0 +1,1038 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +php_http_cookie_list_t *php_http_cookie_list_init(php_http_cookie_list_t *list TSRMLS_DC) +{ + if (!list) { + list = emalloc(sizeof(*list)); + } + + zend_hash_init(&list->cookies, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_init(&list->extras, 0, NULL, ZVAL_PTR_DTOR, 0); + + list->path = NULL; + list->domain = NULL; + list->expires = -1; + list->max_age = -1; + list->flags = 0; + + TSRMLS_SET_CTX(list->ts); + + return list; +} + +php_http_cookie_list_t *php_http_cookie_list_copy(php_http_cookie_list_t *from, php_http_cookie_list_t *to) +{ + TSRMLS_FETCH_FROM_CTX(from->ts); + + to = php_http_cookie_list_init(to TSRMLS_CC); + + array_copy(&from->cookies, &to->cookies); + array_copy(&from->extras, &to->extras); + + STR_SET(to->path, from->path ? estrdup(from->path) : NULL); + STR_SET(to->domain, from->domain ? estrdup(from->domain) : NULL); + to->expires = from->expires; + to->max_age = from->max_age; + to->flags = from->flags; + + return to; +} + +void php_http_cookie_list_dtor(php_http_cookie_list_t *list) +{ + if (list) { + zend_hash_destroy(&list->cookies); + zend_hash_destroy(&list->extras); + + STR_SET(list->path, NULL); + STR_SET(list->domain, NULL); + } +} + + + +void php_http_cookie_list_free(php_http_cookie_list_t **list) +{ + if (*list) { + php_http_cookie_list_dtor(*list); + efree(*list); + *list = NULL; + } +} + +const char *php_http_cookie_list_get_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, zval **zcookie) +{ + zval **cookie; + if ((SUCCESS != zend_symtable_find(&list->cookies, name, name_len + 1, (void *) &cookie)) || (Z_TYPE_PP(cookie) != IS_STRING)) { + return NULL; + } + if (zcookie) { + *zcookie = *cookie; + } + return Z_STRVAL_PP(cookie); +} + +const char *php_http_cookie_list_get_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, zval **zextra) +{ + zval **extra; + + if ((SUCCESS != zend_symtable_find(&list->extras, name, name_len + 1, (void *) &extra)) || (Z_TYPE_PP(extra) != IS_STRING)) { + return NULL; + } + if (zextra) { + *zextra = *extra; + } + return Z_STRVAL_PP(extra); +} + +void php_http_cookie_list_add_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len) +{ + zval *cookie_value; + + MAKE_STD_ZVAL(cookie_value); + ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0); + zend_symtable_update(&list->cookies, name, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL); +} + +void php_http_cookie_list_add_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len) +{ + zval *cookie_value; + + MAKE_STD_ZVAL(cookie_value); + ZVAL_STRINGL(cookie_value, estrndup(value, value_len), value_len, 0); + zend_symtable_update(&list->extras, name, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL); +} + +#define _KEY_IS(s) (key->len == sizeof(s) && !strncasecmp(key->str, (s), key->len)) +static void add_entry(php_http_cookie_list_t *list, char **allowed_extras, long flags, php_http_array_hashkey_t *key, zval *val) +{ + zval *arg = php_http_zsep(1, IS_STRING, val); + + if (!(flags & PHP_HTTP_COOKIE_PARSE_RAW)) { + Z_STRLEN_P(arg) = php_raw_url_decode(Z_STRVAL_P(arg), Z_STRLEN_P(arg)); + } + + if _KEY_IS("path") { + STR_SET(list->path, estrndup(Z_STRVAL_P(arg), Z_STRLEN_P(arg))); + } else if _KEY_IS("domain") { + STR_SET(list->domain, estrndup(Z_STRVAL_P(arg), Z_STRLEN_P(arg))); + } else if _KEY_IS("expires") { + char *date = estrndup(Z_STRVAL_P(arg), Z_STRLEN_P(arg)); + list->expires = php_parse_date(date, NULL); + efree(date); + } else if _KEY_IS("max-age") { + list->max_age = strtol(Z_STRVAL_P(arg), NULL, 10); + } else if _KEY_IS("secure") { + list->flags |= PHP_HTTP_COOKIE_SECURE; + } else if _KEY_IS("httpOnly") { + list->flags |= PHP_HTTP_COOKIE_HTTPONLY; + } else { + /* check for extra */ + if (allowed_extras) { + char **ae = allowed_extras; + + php_http_array_hashkey_stringify(key); + for (; *ae; ++ae) { + if (!strncasecmp(key->str, *ae, key->len)) { + if (key->type == HASH_KEY_IS_LONG) { + zend_hash_index_update(&list->extras, key->num, (void *) &arg, sizeof(zval *), NULL); + } else { + zend_hash_update(&list->extras, key->str, key->len, (void *) &arg, sizeof(zval *), NULL); + } + php_http_array_hashkey_stringfree(key); + return; + } + } + php_http_array_hashkey_stringfree(key); + } + + /* cookie */ + if (key->type == HASH_KEY_IS_LONG) { + zend_hash_index_update(&list->cookies, key->num, (void *) &arg, sizeof(zval *), NULL); + } else { + zend_hash_update(&list->cookies, key->str, key->len, (void *) &arg, sizeof(zval *), NULL); + } + return; + } + zval_ptr_dtor(&arg); +} + +php_http_cookie_list_t *php_http_cookie_list_parse(php_http_cookie_list_t *list, const char *str, size_t len, long flags, char **allowed_extras TSRMLS_DC) +{ + php_http_params_opts_t opts; + HashTable params; + HashPosition pos1, pos2; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + zval **param, **val, **args, **arg; + + php_http_params_opts_default_get(&opts); + opts.input.str = estrndup(str, len); + opts.input.len = len; + opts.param = NULL; + zend_hash_init(¶ms, 10, NULL, ZVAL_PTR_DTOR, 0); + php_http_params_parse(¶ms, &opts TSRMLS_CC); + efree(opts.input.str); + + list = php_http_cookie_list_init(list TSRMLS_CC); + FOREACH_HASH_KEYVAL(pos1, ¶ms, key, param) { + if (Z_TYPE_PP(param) == IS_ARRAY) { + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(param), ZEND_STRS("value"), (void *) &val)) { + add_entry(list, NULL, flags, &key, *val); + } + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(param), ZEND_STRS("arguments"), (void *) &args) && Z_TYPE_PP(args) == IS_ARRAY) { + FOREACH_KEYVAL(pos2, *args, key, arg) { + add_entry(list, allowed_extras, flags, &key, *arg); + } + } + } + } + zend_hash_destroy(¶ms); + + return list; +} + +void php_http_cookie_list_to_struct(php_http_cookie_list_t *list, zval *strct) +{ + zval array, *cookies, *extras; + TSRMLS_FETCH_FROM_CTX(list->ts); + + INIT_PZVAL_ARRAY(&array, HASH_OF(strct)); + + MAKE_STD_ZVAL(cookies); + array_init(cookies); + zend_hash_copy(Z_ARRVAL_P(cookies), &list->cookies, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + add_assoc_zval(&array, "cookies", cookies); + + MAKE_STD_ZVAL(extras); + array_init(extras); + zend_hash_copy(Z_ARRVAL_P(extras), &list->extras, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + add_assoc_zval(&array, "extras", extras); + + add_assoc_long(&array, "flags", list->flags); + add_assoc_long(&array, "expires", (long) list->expires); + add_assoc_long(&array, "max-age", (long) list->max_age); + add_assoc_string(&array, "path", STR_PTR(list->path), 1); + add_assoc_string(&array, "domain", STR_PTR(list->domain), 1); +} + +php_http_cookie_list_t *php_http_cookie_list_from_struct(php_http_cookie_list_t *list, zval *strct TSRMLS_DC) +{ + zval **tmp, *cpy; + HashTable *ht = HASH_OF(strct); + + list = php_http_cookie_list_init(list TSRMLS_CC); + + if (SUCCESS == zend_hash_find(ht, "cookies", sizeof("cookies"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_ARRAY) { + zend_hash_copy(&list->cookies, Z_ARRVAL_PP(tmp), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + } + if (SUCCESS == zend_hash_find(ht, "extras", sizeof("extras"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_ARRAY) { + zend_hash_copy(&list->extras, Z_ARRVAL_PP(tmp), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + } + if (SUCCESS == zend_hash_find(ht, "flags", sizeof("flags"), (void *) &tmp)) { + cpy = php_http_ztyp(IS_LONG, *tmp); + list->flags = Z_LVAL_P(cpy); + zval_ptr_dtor(&cpy); + } + if (SUCCESS == zend_hash_find(ht, "expires", sizeof("expires"), (void *) &tmp)) { + if (Z_TYPE_PP(tmp) == IS_LONG) { + list->expires = Z_LVAL_PP(tmp); + } else { + long lval; + + cpy = php_http_ztyp(IS_STRING, *tmp); + if (IS_LONG == is_numeric_string(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy), &lval, NULL, 0)) { + list->expires = lval; + } else { + list->expires = php_parse_date(Z_STRVAL_P(cpy), NULL); + } + + zval_ptr_dtor(&cpy); + } + } + if (SUCCESS == zend_hash_find(ht, "max-age", sizeof("max-age"), (void *) &tmp)) { + if (Z_TYPE_PP(tmp) == IS_LONG) { + list->max_age = Z_LVAL_PP(tmp); + } else { + long lval; + + cpy = php_http_ztyp(IS_STRING, *tmp); + if (IS_LONG == is_numeric_string(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy), &lval, NULL, 0)) { + list->max_age = lval; + } + + zval_ptr_dtor(&cpy); + } + } + if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_STRING) { + list->path = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } + if (SUCCESS == zend_hash_find(ht, "domain", sizeof("domain"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_STRING) { + list->domain = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } + + return list; +} + +static inline void append_encoded(php_http_buffer_t *buf, const char *key, size_t key_len, const char *val, size_t val_len) +{ + char *enc_str[2]; + int enc_len[2]; + + enc_str[0] = php_raw_url_encode(key, key_len, &enc_len[0]); + enc_str[1] = php_raw_url_encode(val, val_len, &enc_len[1]); + + php_http_buffer_append(buf, enc_str[0], enc_len[0]); + php_http_buffer_appends(buf, "="); + php_http_buffer_append(buf, enc_str[1], enc_len[1]); + php_http_buffer_appends(buf, "; "); + + efree(enc_str[0]); + efree(enc_str[1]); +} + +void php_http_cookie_list_to_string(php_http_cookie_list_t *list, char **str, size_t *len) +{ + php_http_buffer_t buf; + zval **val; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + HashPosition pos; + TSRMLS_FETCH_FROM_CTX(list->ts); + + php_http_buffer_init(&buf); + + FOREACH_HASH_KEYVAL(pos, &list->cookies, key, val) { + zval *tmp = php_http_ztyp(IS_STRING, *val); + + php_http_array_hashkey_stringify(&key); + append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + php_http_array_hashkey_stringfree(&key); + + zval_ptr_dtor(&tmp); + } + + if (list->domain && *list->domain) { + php_http_buffer_appendf(&buf, "domain=%s; ", list->domain); + } + if (list->path && *list->path) { + php_http_buffer_appendf(&buf, "path=%s; ", list->path); + } + if (list->expires >= 0) { + char *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), list->expires, 0 TSRMLS_CC); + php_http_buffer_appendf(&buf, "expires=%s; ", date); + efree(date); + } + if (list->max_age >= 0) { + php_http_buffer_appendf(&buf, "max-age=%ld; ", list->max_age); + } + + FOREACH_HASH_KEYVAL(pos, &list->extras, key, val) { + zval *tmp = php_http_ztyp(IS_STRING, *val); + + php_http_array_hashkey_stringify(&key); + append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + php_http_array_hashkey_stringfree(&key); + + zval_ptr_dtor(&tmp); + } + + if (list->flags & PHP_HTTP_COOKIE_SECURE) { + php_http_buffer_appends(&buf, "secure; "); + } + if (list->flags & PHP_HTTP_COOKIE_HTTPONLY) { + php_http_buffer_appends(&buf, "httpOnly; "); + } + + php_http_buffer_fix(&buf); + *str = buf.data; + *len = buf.used; +} + + + +static zend_object_handlers php_http_cookie_object_handlers; + +zend_object_value php_http_cookie_object_new(zend_class_entry *ce TSRMLS_DC) +{ + return php_http_cookie_object_new_ex(ce, NULL, NULL TSRMLS_CC); +} + +zend_object_value php_http_cookie_object_new_ex(zend_class_entry *ce, php_http_cookie_list_t *list, php_http_cookie_object_t **ptr TSRMLS_DC) +{ + php_http_cookie_object_t *o; + + o = ecalloc(sizeof(*o), 1); + zend_object_std_init((zend_object *) o, ce TSRMLS_CC); + object_properties_init((zend_object *) o, ce); + + if (list) { + o->list = list; + } + + if (ptr) { + *ptr = o; + } + + o->zv.handle = zend_objects_store_put(o, NULL, php_http_cookie_object_free, NULL TSRMLS_CC); + o->zv.handlers = &php_http_cookie_object_handlers; + + return o->zv; +} + +#define PHP_HTTP_COOKIE_OBJECT_INIT(obj) \ + do { \ + if (!obj->list) { \ + obj->list = php_http_cookie_list_init(NULL TSRMLS_CC); \ + } \ + } while(0) + +zend_object_value php_http_cookie_object_clone(zval *this_ptr TSRMLS_DC) +{ + php_http_cookie_object_t *new_obj, *old_obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zend_object_value ov; + + PHP_HTTP_COOKIE_OBJECT_INIT(old_obj); + + ov = php_http_cookie_object_new_ex(old_obj->zo.ce, php_http_cookie_list_copy(old_obj->list, NULL), &new_obj TSRMLS_CC); + zend_objects_clone_members((zend_object *) new_obj, ov, (zend_object *) old_obj, Z_OBJ_HANDLE_P(getThis()) TSRMLS_CC); + + return ov; +} + +void php_http_cookie_object_free(void *object TSRMLS_DC) +{ + php_http_cookie_object_t *obj = object; + + php_http_cookie_list_free(&obj->list); + zend_object_std_dtor((zend_object *) obj TSRMLS_CC); + efree(obj); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie___construct, 0, 0, 0) + ZEND_ARG_INFO(0, cookie_string) + ZEND_ARG_INFO(0, parser_flags) + ZEND_ARG_INFO(0, allowed_extras) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, __construct) +{ + php_http_cookie_object_t *obj; + zval *zcookie = NULL; + long flags = 0; + char **ae = NULL; + HashTable *allowed_extras = NULL; + zend_error_handling zeh; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!lH", &zcookie, &flags, &allowed_extras), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + zend_replace_error_handling(EH_THROW, php_http_exception_runtime_class_entry, &zeh TSRMLS_CC); + if (zcookie) { + + if (allowed_extras && zend_hash_num_elements(allowed_extras)) { + char **ae_ptr = safe_emalloc(zend_hash_num_elements(allowed_extras) + 1, sizeof(char *), 0); + HashPosition pos; + zval **val; + + ae = ae_ptr; + FOREACH_HASH_VAL(pos, allowed_extras, val) { + zval *cpy = php_http_ztyp(IS_STRING, *val); + + *ae_ptr++ = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); + zval_ptr_dtor(&cpy); + } + *ae_ptr = NULL; + } + + switch (Z_TYPE_P(zcookie)) { + case IS_OBJECT: + if (instanceof_function(Z_OBJCE_P(zcookie), php_http_cookie_class_entry TSRMLS_CC)) { + php_http_cookie_object_t *zco = zend_object_store_get_object(zcookie TSRMLS_CC); + + if (zco->list) { + obj->list = php_http_cookie_list_copy(zco->list, NULL); + } + break; + } + /* no break */ + case IS_ARRAY: + obj->list = php_http_cookie_list_from_struct(obj->list, zcookie TSRMLS_CC); + break; + default: { + zval *cpy = php_http_ztyp(IS_STRING, zcookie); + + obj->list = php_http_cookie_list_parse(obj->list, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy), flags, ae TSRMLS_CC); + zval_ptr_dtor(&cpy); + break; + } + } + + if (ae) { + char **ae_ptr; + + for (ae_ptr = ae; *ae_ptr; ++ae_ptr) { + efree(*ae_ptr); + } + efree(ae); + } + } + zend_restore_error_handling(&zeh TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getCookies, 0, 0, 0) +ZEND_END_ARG_INFO();; +static PHP_METHOD(HttpCookie, getCookies) +{ + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + array_init(return_value); + array_copy(&obj->list->cookies, Z_ARRVAL_P(return_value)); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setCookies, 0, 0, 0) + ZEND_ARG_INFO(0, cookies) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, setCookies) +{ + HashTable *cookies = NULL; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|H", &cookies), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + zend_hash_clean(&obj->list->cookies); + if (cookies) { + array_copy(cookies, &obj->list->cookies); + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addCookies, 0, 0, 1) + ZEND_ARG_INFO(0, cookies) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, addCookies) +{ + HashTable *cookies = NULL; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &cookies), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + array_join(cookies, &obj->list->cookies, 1, ARRAY_JOIN_STRONLY); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getExtras, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, getExtras) +{ + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + array_init(return_value); + array_copy(&obj->list->extras, Z_ARRVAL_P(return_value)); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setExtras, 0, 0, 0) + ZEND_ARG_INFO(0, extras) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, setExtras) +{ + HashTable *extras = NULL; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|H", &extras), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + zend_hash_clean(&obj->list->extras); + if (extras) { + array_copy(extras, &obj->list->extras); + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addExtras, 0, 0, 1) + ZEND_ARG_INFO(0, extras) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, addExtras) +{ + HashTable *extras = NULL; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &extras), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + array_join(extras, &obj->list->extras, 1, ARRAY_JOIN_STRONLY); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getCookie, 0, 0, 1) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, getCookie) +{ + char *name_str; + int name_len; + zval *zvalue; + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + if (php_http_cookie_list_get_cookie(obj->list, name_str, name_len, &zvalue)) { + RETURN_ZVAL(zvalue, 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setCookie, 0, 0, 1) + ZEND_ARG_INFO(0, cookie_name) + ZEND_ARG_INFO(0, cookie_value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, setCookie) +{ + char *name_str, *value_str = NULL; + int name_len, value_len = 0; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + if (!value_str) { + php_http_cookie_list_del_cookie(obj->list, name_str, name_len); + } else { + php_http_cookie_list_add_cookie(obj->list, name_str, name_len, value_str, value_len); + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addCookie, 0, 0, 2) + ZEND_ARG_INFO(0, cookie_name) + ZEND_ARG_INFO(0, cookie_value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, addCookie) +{ + char *name_str, *value_str; + int name_len, value_len; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + php_http_cookie_list_add_cookie(obj->list, name_str, name_len, value_str, value_len); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getExtra, 0, 0, 1) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, getExtra) +{ + char *name_str; + int name_len; + zval *zvalue; + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + if (php_http_cookie_list_get_extra(obj->list, name_str, name_len, &zvalue)) { + RETURN_ZVAL(zvalue, 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setExtra, 0, 0, 1) + ZEND_ARG_INFO(0, extra_name) + ZEND_ARG_INFO(0, extra_value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, setExtra) +{ + char *name_str, *value_str = NULL; + int name_len, value_len = 0; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + if (!value_str) { + php_http_cookie_list_del_extra(obj->list, name_str, name_len); + } else { + php_http_cookie_list_add_extra(obj->list, name_str, name_len, value_str, value_len); + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addExtra, 0, 0, 2) + ZEND_ARG_INFO(0, extra_name) + ZEND_ARG_INFO(0, extra_value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, addExtra) +{ + char *name_str, *value_str; + int name_len, value_len; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + php_http_cookie_list_add_extra(obj->list, name_str, name_len, value_str, value_len); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getDomain, 0, 0, 0) +ZEND_END_ARG_INFO();; +static PHP_METHOD(HttpCookie, getDomain) +{ + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + if (obj->list->domain) { + RETURN_STRING(obj->list->domain, 1); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setDomain, 0, 0, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, setDomain) +{ + char *domain_str = NULL; + int domain_len = 0; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &domain_str, &domain_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + STR_SET(obj->list->domain, domain_str ? estrndup(domain_str, domain_len) : NULL); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getPath, 0, 0, 0) +ZEND_END_ARG_INFO();; +static PHP_METHOD(HttpCookie, getPath) +{ + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + if (obj->list->path) { + RETURN_STRING(obj->list->path, 1); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setPath, 0, 0, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, setPath) +{ + char *path_str = NULL; + int path_len = 0; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &path_str, &path_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + STR_SET(obj->list->path, path_str ? estrndup(path_str, path_len) : NULL); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getExpires, 0, 0, 0) +ZEND_END_ARG_INFO();; +static PHP_METHOD(HttpCookie, getExpires) +{ + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + RETURN_LONG(obj->list->expires); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setExpires, 0, 0, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, setExpires) +{ + long ts = -1; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &ts), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + obj->list->expires = ts; + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getMaxAge, 0, 0, 0) +ZEND_END_ARG_INFO();; +static PHP_METHOD(HttpCookie, getMaxAge) +{ + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + RETURN_LONG(obj->list->max_age); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setMaxAge, 0, 0, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, setMaxAge) +{ + long ts = -1; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &ts), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + obj->list->max_age = ts; + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getFlags, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, getFlags) +{ + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + RETURN_LONG(obj->list->flags); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setFlags, 0, 0, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpCookie, setFlags) +{ + long flags = 0; + php_http_cookie_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + obj->list->flags = flags; + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_toString, 0, 0, 0) +ZEND_END_ARG_INFO();; +static PHP_METHOD(HttpCookie, toString) +{ + php_http_cookie_object_t *obj; + char *str; + size_t len; + + if (SUCCESS != zend_parse_parameters_none()) { + RETURN_EMPTY_STRING(); + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + php_http_cookie_list_to_string(obj->list, &str, &len); + + RETURN_STRINGL(str, len, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_toArray, 0, 0, 0) +ZEND_END_ARG_INFO();; +static PHP_METHOD(HttpCookie, toArray) +{ + php_http_cookie_object_t *obj; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_COOKIE_OBJECT_INIT(obj); + + array_init(return_value); + php_http_cookie_list_to_struct(obj->list, return_value); +} + +static zend_function_entry php_http_cookie_methods[] = { + PHP_ME(HttpCookie, __construct, ai_HttpCookie___construct, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, getCookies, ai_HttpCookie_getCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, setCookies, ai_HttpCookie_setCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, addCookies, ai_HttpCookie_addCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, getCookie, ai_HttpCookie_getCookie, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, setCookie, ai_HttpCookie_setCookie, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, addCookie, ai_HttpCookie_addCookie, ZEND_ACC_PUBLIC) + + PHP_ME(HttpCookie, getExtras, ai_HttpCookie_getExtras, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, setExtras, ai_HttpCookie_setExtras, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, addExtras, ai_HttpCookie_addExtras, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, getExtra, ai_HttpCookie_getExtra, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, setExtra, ai_HttpCookie_setExtra, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, addExtra, ai_HttpCookie_addExtra, ZEND_ACC_PUBLIC) + + PHP_ME(HttpCookie, getDomain, ai_HttpCookie_getDomain, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, setDomain, ai_HttpCookie_setDomain, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, getPath, ai_HttpCookie_getPath, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, setPath, ai_HttpCookie_setPath, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, getExpires, ai_HttpCookie_getExpires, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, setExpires, ai_HttpCookie_setExpires, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, getMaxAge, ai_HttpCookie_getMaxAge, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, setMaxAge, ai_HttpCookie_setMaxAge, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, getFlags, ai_HttpCookie_getFlags, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, setFlags, ai_HttpCookie_setFlags, ZEND_ACC_PUBLIC) + + PHP_ME(HttpCookie, toArray, ai_HttpCookie_toArray, ZEND_ACC_PUBLIC) + PHP_ME(HttpCookie, toString, ai_HttpCookie_toString, ZEND_ACC_PUBLIC) + ZEND_MALIAS(HttpCookie, __toString, toString, ai_HttpCookie_toString, ZEND_ACC_PUBLIC) + + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_cookie_class_entry; + +PHP_MINIT_FUNCTION(http_cookie) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "Cookie", php_http_cookie_methods); + php_http_cookie_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + php_http_cookie_class_entry->create_object = php_http_cookie_object_new; + memcpy(&php_http_cookie_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + php_http_cookie_object_handlers.clone_obj = php_http_cookie_object_clone; + + zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_COOKIE_PARSE_RAW TSRMLS_CC); + zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("SECURE"), PHP_HTTP_COOKIE_SECURE TSRMLS_CC); + zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("HTTPONLY"), PHP_HTTP_COOKIE_HTTPONLY TSRMLS_CC); + + return SUCCESS; +} + + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_cookie.h b/php_http_cookie.h new file mode 100644 index 0000000..9d5b7c8 --- /dev/null +++ b/php_http_cookie.h @@ -0,0 +1,84 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_COOKIE_H +#define PHP_HTTP_COOKIE_H + +#define PHP_HTTP_COOKIE_SECURE 0x10L +#define PHP_HTTP_COOKIE_HTTPONLY 0x20L + +#define PHP_HTTP_COOKIE_PARSE_RAW 0x01L + +/* + generally a netscape cookie compliant struct, recognizing httpOnly attribute, too; + cookie params like those from rfc2109 and rfc2965 are just put into extras, if + one specifies them in allowed extras, else they're treated like cookies themself +*/ +typedef struct php_http_cookie_list { + HashTable cookies; + HashTable extras; + long flags; + char *path; + char *domain; + time_t expires; + time_t max_age; + +#ifdef ZTS + void ***ts; +#endif +} php_http_cookie_list_t; + +PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_init(php_http_cookie_list_t *list TSRMLS_DC); +PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_parse(php_http_cookie_list_t *list, const char *str, size_t len, long flags, char **allowed_extras TSRMLS_DC); +PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_copy(php_http_cookie_list_t *from, php_http_cookie_list_t *to); +PHP_HTTP_API void php_http_cookie_list_dtor(php_http_cookie_list_t *list); +PHP_HTTP_API void php_http_cookie_list_free(php_http_cookie_list_t **list); + +#define php_http_cookie_list_has_cookie(list, name, name_len) zend_symtable_exists(&(list)->cookies, (name), (name_len)+1) +#define php_http_cookie_list_del_cookie(list, name, name_len) zend_symtable_del(&(list)->cookies, (name), (name_len)+1) +PHP_HTTP_API void php_http_cookie_list_add_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len); +PHP_HTTP_API const char *php_http_cookie_list_get_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, zval **cookie); + +#define php_http_cookie_list_has_extra(list, name, name_len) zend_symtable_exists(&(list)->extras, (name), (name_len)+1) +#define php_http_cookie_list_del_extra(list, name, name_len) zend_symtable_del(&(list)->extras, (name), (name_len)+1) +PHP_HTTP_API void php_http_cookie_list_add_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len); +PHP_HTTP_API const char *php_http_cookie_list_get_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, zval **extra); + +PHP_HTTP_API void php_http_cookie_list_to_string(php_http_cookie_list_t *list, char **str, size_t *len); +PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_from_struct(php_http_cookie_list_t *list, zval *strct TSRMLS_DC); +PHP_HTTP_API void php_http_cookie_list_to_struct(php_http_cookie_list_t *list, zval *strct); + +PHP_HTTP_API zend_class_entry *php_http_cookie_class_entry; + +typedef struct php_http_cookie_object { + zend_object zo; + zend_object_value zv; + php_http_cookie_list_t *list; +} php_http_cookie_object_t; + +zend_object_value php_http_cookie_object_new(zend_class_entry *ce TSRMLS_DC); +zend_object_value php_http_cookie_object_new_ex(zend_class_entry *ce, php_http_cookie_list_t *list, php_http_cookie_object_t **obj TSRMLS_DC); +zend_object_value php_http_cookie_object_clone(zval *this_ptr TSRMLS_DC); +void php_http_cookie_object_free(void *object TSRMLS_DC); + +PHP_MINIT_FUNCTION(http_cookie); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_cookie_api.h b/php_http_cookie_api.h deleted file mode 100644 index bf07940..0000000 --- a/php_http_cookie_api.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_COOKIE_API_H -#define PHP_HTTP_COOKIE_API_H - -#define HTTP_COOKIE_SECURE 0x10L -#define HTTP_COOKIE_HTTPONLY 0x20L - -#define HTTP_COOKIE_PARSE_RAW 0x01L - -extern PHP_MINIT_FUNCTION(http_cookie); - -/* - generally a netscape cookie compliant struct, recognizing httpOnly attribute, too; - cookie params like those from rfc2109 and rfc2965 are just put into extras, if - one specifies them in allowed extras, else they're treated like cookies themself -*/ -typedef struct _http_cookie_list_t { - HashTable cookies; - HashTable extras; - long flags; - char *path; - char *domain; - time_t expires; -} http_cookie_list; - -#define http_cookie_list_new() _http_cookie_list_init(NULL ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -#define http_cookie_list_init(l) _http_cookie_list_init((l) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API http_cookie_list *_http_cookie_list_init(http_cookie_list *list ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); - -#define http_cookie_list_dtor(l) _http_cookie_list_dtor((l) TSRMLS_CC) -PHP_HTTP_API void _http_cookie_list_dtor(http_cookie_list *list TSRMLS_DC); - -#define http_cookie_list_free(l) _http_cookie_list_free((l) TSRMLS_CC) -PHP_HTTP_API void _http_cookie_list_free(http_cookie_list **list TSRMLS_DC); - -#define http_cookie_list_has_cookie(list, name, name_len) zend_hash_exists(&(list)->cookies, (name), (name_len)+1) -#define http_cookie_list_has_extra(list, name, name_len) zend_hash_exists(&(list)->extras, (name), (name_len)+1) - -#define http_cookie_list_add_cookie(l, n, nl, v, vl) _http_cookie_list_add_cookie((l), (n), (nl), (v), (vl) TSRMLS_CC) -PHP_HTTP_API void _http_cookie_list_add_cookie(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC); - -#define http_cookie_list_add_extra(l, n , nl, v, vl) _http_cookie_list_add_extra((l), (n), (nl), (v), (vl) TSRMLS_CC) -PHP_HTTP_API void _http_cookie_list_add_extra(http_cookie_list *list, const char *name, size_t name_len, const char *value, size_t value_len TSRMLS_DC); - -#define http_cookie_list_get_cookie(l, n, nl) _http_cookie_list_get_cookie((l), (n), (nl) TSRMLS_CC) -PHP_HTTP_API const char *_http_cookie_list_get_cookie(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC); - -#define http_cookie_list_get_extra(l, n, nl) _http_cookie_list_get_extra((l), (n), (nl) TSRMLS_CC) -PHP_HTTP_API const char *_http_cookie_list_get_extra(http_cookie_list *list, const char *name, size_t name_len TSRMLS_DC); - -#define http_parse_cookie(s) _http_parse_cookie_ex(NULL, (s), 0, NULL TSRMLS_CC) -#define http_parse_cookie_ex(l, s, f, a) _http_parse_cookie_ex((l), (s), (f), (a) TSRMLS_CC) -PHP_HTTP_API http_cookie_list *_http_parse_cookie_ex(http_cookie_list * list, const char *string, long flags, char **allowed_extras TSRMLS_DC); - -#define http_cookie_list_tostruct(l, s) _http_cookie_list_tostruct((l), (s) TSRMLS_CC) -PHP_HTTP_API void _http_cookie_list_tostruct(http_cookie_list *list, zval *strct TSRMLS_DC); - -#define http_cookie_list_fromstruct(l, s) _http_cookie_list_fromstruct((l), (s) TSRMLS_CC) -PHP_HTTP_API http_cookie_list *_http_cookie_list_fromstruct(http_cookie_list *list, zval *strct TSRMLS_DC); - -#define http_cookie_list_tostring(l, str, len) _http_cookie_list_tostring((l), (str), (len) TSRMLS_CC) -PHP_HTTP_API void _http_cookie_list_tostring(http_cookie_list *list, char **str, size_t *len TSRMLS_DC); - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/php_http_curl.c b/php_http_curl.c new file mode 100644 index 0000000..6607ca1 --- /dev/null +++ b/php_http_curl.c @@ -0,0 +1,151 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#if PHP_HTTP_HAVE_CURL + +#if defined(ZTS) && defined(PHP_HTTP_HAVE_SSL) +# ifdef PHP_WIN32 +# define PHP_HTTP_NEED_OPENSSL_TSL +# include +# else /* !PHP_WIN32 */ +# if defined(PHP_HTTP_HAVE_OPENSSL) +# define PHP_HTTP_NEED_OPENSSL_TSL +# include +# elif defined(PHP_HTTP_HAVE_GNUTLS) +# define PHP_HTTP_NEED_GNUTLS_TSL +# include +# else +# warning \ + "libcurl was compiled with SSL support, but configure could not determine which" \ + "library was used; thus no SSL crypto locking callbacks will be set, which may " \ + "cause random crashes on SSL requests" +# endif /* PHP_HTTP_HAVE_OPENSSL || PHP_HTTP_HAVE_GNUTLS */ +# endif /* PHP_WIN32 */ +#endif /* ZTS && PHP_HTTP_HAVE_SSL */ + + +#ifdef PHP_HTTP_NEED_OPENSSL_TSL +static MUTEX_T *php_http_openssl_tsl = NULL; + +static void php_http_openssl_thread_lock(int mode, int n, const char * file, int line) +{ + if (mode & CRYPTO_LOCK) { + tsrm_mutex_lock(php_http_openssl_tsl[n]); + } else { + tsrm_mutex_unlock(php_http_openssl_tsl[n]); + } +} + +static ulong php_http_openssl_thread_id(void) +{ + return (ulong) tsrm_thread_id(); +} +#endif +#ifdef PHP_HTTP_NEED_GNUTLS_TSL +static int php_http_gnutls_mutex_create(void **m) +{ + if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) { + return SUCCESS; + } else { + return FAILURE; + } +} + +static int php_http_gnutls_mutex_destroy(void **m) +{ + tsrm_mutex_free(*((MUTEX_T *) m)); + return SUCCESS; +} + +static int php_http_gnutls_mutex_lock(void **m) +{ + return tsrm_mutex_lock(*((MUTEX_T *) m)); +} + +static int php_http_gnutls_mutex_unlock(void **m) +{ + return tsrm_mutex_unlock(*((MUTEX_T *) m)); +} + +static struct gcry_thread_cbs php_http_gnutls_tsl = { + GCRY_THREAD_OPTION_USER, + NULL, + php_http_gnutls_mutex_create, + php_http_gnutls_mutex_destroy, + php_http_gnutls_mutex_lock, + php_http_gnutls_mutex_unlock +}; +#endif + + +PHP_MINIT_FUNCTION(http_curl) +{ +#ifdef PHP_HTTP_NEED_OPENSSL_TSL + /* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */ + if (!CRYPTO_get_id_callback()) { + int i, c = CRYPTO_num_locks(); + + php_http_openssl_tsl = malloc(c * sizeof(MUTEX_T)); + + for (i = 0; i < c; ++i) { + php_http_openssl_tsl[i] = tsrm_mutex_alloc(); + } + + CRYPTO_set_id_callback(php_http_openssl_thread_id); + CRYPTO_set_locking_callback(php_http_openssl_thread_lock); + } +#endif +#ifdef PHP_HTTP_NEED_GNUTLS_TSL + gcry_control(GCRYCTL_SET_THREAD_CBS, &php_http_gnutls_tsl); +#endif + + if (CURLE_OK != curl_global_init(CURL_GLOBAL_ALL)) { + return FAILURE; + } + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(http_curl) +{ + curl_global_cleanup(); +#ifdef PHP_HTTP_NEED_OPENSSL_TSL + if (php_http_openssl_tsl) { + int i, c = CRYPTO_num_locks(); + + CRYPTO_set_id_callback(NULL); + CRYPTO_set_locking_callback(NULL); + + for (i = 0; i < c; ++i) { + tsrm_mutex_free(php_http_openssl_tsl[i]); + } + + free(php_http_openssl_tsl); + php_http_openssl_tsl = NULL; + } +#endif + return SUCCESS; +} + +#endif /* PHP_HTTP_HAVE_CURL */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_date_api.h b/php_http_curl.h similarity index 62% rename from php_http_date_api.h rename to php_http_curl.h index f33e275..4621d5a 100644 --- a/php_http_date_api.h +++ b/php_http_curl.h @@ -6,23 +6,24 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | + | Copyright (c) 2004-2013, Michael Wallner | +--------------------------------------------------------------------+ */ -/* $Id$ */ +#ifndef PHP_HTTP_CURL_H +#define PHP_HTTP_CURL_H -#ifndef PHP_HTTP_DATE_API_H -#define PHP_HTTP_DATE_API_H +#if PHP_HTTP_HAVE_CURL -#define http_date(t) _http_date((t) TSRMLS_CC) -PHP_HTTP_API char *_http_date(time_t t TSRMLS_DC); +#include +#define PHP_HTTP_CURL_VERSION(x, y, z) (LIBCURL_VERSION_NUM >= (((x)<<16) + ((y)<<8) + (z))) -#define http_parse_date(d) _http_parse_date_ex((d), 0 TSRMLS_CC) -#define http_parse_date_ex(d, s) _http_parse_date_ex((d), (s) TSRMLS_CC) -PHP_HTTP_API time_t _http_parse_date_ex(const char *date, zend_bool silent TSRMLS_DC); +PHP_MINIT_FUNCTION(http_curl); +PHP_MSHUTDOWN_FUNCTION(http_curl); -#endif +#endif /* PHP_HTTP_HAVE_CURL */ + +#endif /* PHP_HTTP_CURL_H */ /* * Local variables: diff --git a/php_http_deflatestream_object.h b/php_http_deflatestream_object.h deleted file mode 100644 index 3d20328..0000000 --- a/php_http_deflatestream_object.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_DEFLATESTREAM_OBJECT_H -#define PHP_HTTP_DEFLATESTREAM_OBJECT_H -#ifdef HTTP_HAVE_ZLIB -#ifdef ZEND_ENGINE_2 - -typedef struct _http_deflatestream_object_t { - zend_object zo; - http_encoding_stream *stream; -} http_deflatestream_object; - -extern zend_class_entry *http_deflatestream_object_ce; -extern zend_function_entry http_deflatestream_object_fe[]; - -extern PHP_MINIT_FUNCTION(http_deflatestream_object); - -#define http_deflatestream_object_new(ce) _http_deflatestream_object_new((ce) TSRMLS_CC) -extern zend_object_value _http_deflatestream_object_new(zend_class_entry *ce TSRMLS_DC); -#define http_deflatestream_object_new_ex(ce, s, ptr) _http_deflatestream_object_new_ex((ce), (s), (ptr) TSRMLS_CC) -extern zend_object_value _http_deflatestream_object_new_ex(zend_class_entry *ce, http_encoding_stream *s, http_deflatestream_object **ptr TSRMLS_DC); -#define http_deflatestream_object_clone(zobj) _http_deflatestream_object_clone_obj(zobj TSRMLS_CC) -extern zend_object_value _http_deflatestream_object_clone_obj(zval *object TSRMLS_DC); -#define http_deflatestream_object_free(o) _http_deflatestream_object_free((o) TSRMLS_CC) -extern void _http_deflatestream_object_free(zend_object *object TSRMLS_DC); - -PHP_METHOD(HttpDeflateStream, __construct); -PHP_METHOD(HttpDeflateStream, factory); -PHP_METHOD(HttpDeflateStream, update); -PHP_METHOD(HttpDeflateStream, flush); -PHP_METHOD(HttpDeflateStream, finish); - -#endif -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_encoding.c b/php_http_encoding.c new file mode 100644 index 0000000..3c5393b --- /dev/null +++ b/php_http_encoding.c @@ -0,0 +1,1228 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#include + +static inline int eol_match(char **line, int *eol_len) +{ + char *ptr = *line; + + while (' ' == *ptr) ++ptr; + + if (ptr == php_http_locate_eol(*line, eol_len)) { + *line = ptr; + return 1; + } else { + return 0; + } +} + +const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC) +{ + int eol_len = 0; + char *n_ptr = NULL; + const char *e_ptr = encoded; + + *decoded_len = 0; + *decoded = ecalloc(1, encoded_len + 1); + + while ((encoded + encoded_len - e_ptr) > 0) { + ulong chunk_len = 0, rest; + + chunk_len = strtoul(e_ptr, &n_ptr, 16); + + /* we could not read in chunk size */ + if (n_ptr == e_ptr) { + /* + * if this is the first turn and there doesn't seem to be a chunk + * size at the begining of the body, do not fail on apparently + * not encoded data and return a copy + */ + if (e_ptr == encoded) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Data does not seem to be chunked encoded"); + memcpy(*decoded, encoded, encoded_len); + *decoded_len = encoded_len; + decoded[*decoded_len] = '\0'; + return encoded + encoded_len; + } else { + efree(*decoded); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected chunk size at pos %tu of %zu but got trash", n_ptr - encoded, encoded_len); + return NULL; + } + } + + /* reached the end */ + if (!chunk_len) { + /* move over '0' chunked encoding terminator and any new lines */ + do { + switch (*e_ptr) { + case '0': + case '\r': + case '\n': + ++e_ptr; + continue; + } + } while (0); + break; + } + + /* there should be CRLF after the chunk size, but we'll ignore SP+ too */ + if (*n_ptr && !eol_match(&n_ptr, &eol_len)) { + if (eol_len == 2) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected CRLF at pos %tu of %zu but got 0x%02X 0x%02X", n_ptr - encoded, encoded_len, *n_ptr, *(n_ptr + 1)); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr - encoded, encoded_len, *n_ptr); + } + } + n_ptr += eol_len; + + /* chunk size pretends more data than we actually got, so it's probably a truncated message */ + if (chunk_len > (rest = encoded + encoded_len - n_ptr)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Truncated message: chunk size %lu exceeds remaining data size %lu at pos %tu of %zu", chunk_len, rest, n_ptr - encoded, encoded_len); + chunk_len = rest; + } + + /* copy the chunk */ + memcpy(*decoded + *decoded_len, n_ptr, chunk_len); + *decoded_len += chunk_len; + + if (chunk_len == rest) { + e_ptr = n_ptr + chunk_len; + break; + } else { + /* advance to next chunk */ + e_ptr = n_ptr + chunk_len + eol_len; + } + } + + return e_ptr; +} + +static inline int php_http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len) +{ + int status = 0, round = 0; + php_http_buffer_t buffer; + + *buf = NULL; + *len = 0; + + php_http_buffer_init_ex(&buffer, Z->avail_in, PHP_HTTP_BUFFER_INIT_PREALLOC); + + do { + if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(&buffer, buffer.size, 0, 1)) { + status = Z_MEM_ERROR; + } else { + Z->avail_out = buffer.free; + Z->next_out = (Bytef *) buffer.data + buffer.used; +#if 0 + fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out); +#endif + status = inflate(Z, flush); + php_http_buffer_account(&buffer, buffer.free - Z->avail_out); +#if 0 + fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out); +#endif + PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size); + } + } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < PHP_HTTP_INFLATE_ROUNDS); + + if (status == Z_OK || status == Z_STREAM_END) { + php_http_buffer_shrink(&buffer); + php_http_buffer_fix(&buffer); + *buf = buffer.data; + *len = buffer.used; + } else { + php_http_buffer_dtor(&buffer); + } + + return status; +} + +STATUS php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC) +{ + int status, level, wbits, strategy; + z_stream Z; + + PHP_HTTP_DEFLATE_LEVEL_SET(flags, level); + PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits); + PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy); + + memset(&Z, 0, sizeof(z_stream)); + *encoded = NULL; + *encoded_len = 0; + + status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy); + if (Z_OK == status) { + *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len); + *encoded = emalloc(*encoded_len); + + Z.next_in = (Bytef *) data; + Z.next_out = (Bytef *) *encoded; + Z.avail_in = data_len; + Z.avail_out = *encoded_len; + + status = deflate(&Z, Z_FINISH); + deflateEnd(&Z); + + if (Z_STREAM_END == status) { + /* size buffer down to actual length */ + *encoded = erealloc(*encoded, Z.total_out + 1); + (*encoded)[*encoded_len = Z.total_out] = '\0'; + return SUCCESS; + } else { + STR_SET(*encoded, NULL); + *encoded_len = 0; + } + } + + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not deflate data: %s", zError(status)); + return FAILURE; +} + +STATUS php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC) +{ + z_stream Z; + int status, wbits = PHP_HTTP_WINDOW_BITS_ANY; + + memset(&Z, 0, sizeof(z_stream)); + +retry_raw_inflate: + status = inflateInit2(&Z, wbits); + if (Z_OK == status) { + Z.next_in = (Bytef *) data; + Z.avail_in = data_len + 1; /* include the terminating NULL, see #61287 */ + + switch (status = php_http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) { + case Z_STREAM_END: + inflateEnd(&Z); + return SUCCESS; + + case Z_OK: + status = Z_DATA_ERROR; + break; + + case Z_DATA_ERROR: + /* raw deflated data? */ + if (PHP_HTTP_WINDOW_BITS_ANY == wbits) { + inflateEnd(&Z); + wbits = PHP_HTTP_WINDOW_BITS_RAW; + goto retry_raw_inflate; + } + break; + } + inflateEnd(&Z); + + if (decoded_len && *decoded) { + efree(*decoded); + } + } + + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not inflate data: %s", zError(status)); + return FAILURE; +} + +php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags TSRMLS_DC) +{ + int freeme; + + if ((freeme = !s)) { + s = pemalloc(sizeof(*s), (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + } + memset(s, 0, sizeof(*s)); + + s->flags = flags; + TSRMLS_SET_CTX(s->ts); + + if ((s->ops = ops)) { + php_http_encoding_stream_t *ss = s->ops->init(s); + + if (ss) { + return ss; + } + } else { + return s; + } + + if (freeme) { + pefree(s, (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + } + return NULL; +} + +php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to) +{ + TSRMLS_FETCH_FROM_CTX(from->ts); + + if (from->ops->copy) { + int freeme; + php_http_encoding_stream_t *ns; + + if ((freeme = !to)) { + to = pemalloc(sizeof(*to), (from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + } + memset(to, 0, sizeof(*to)); + + to->flags = from->flags; + to->ops = from->ops; + TSRMLS_SET_CTX(to->ts); + + if ((ns = to->ops->copy(from, to))) { + return ns; + } else { + return to; + } + + if (freeme) { + pefree(to, (to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + } + } + + return NULL; +} + +STATUS php_http_encoding_stream_reset(php_http_encoding_stream_t **s) +{ + php_http_encoding_stream_t *ss; + if ((*s)->ops->dtor) { + (*s)->ops->dtor(*s); + } + if ((ss = (*s)->ops->init(*s))) { + *s = ss; + return SUCCESS; + } + return FAILURE; +} + +STATUS php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len) +{ + if (!s->ops->update) { + return FAILURE; + } + return s->ops->update(s, in_str, in_len, out_str, out_len); +} + +STATUS php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *out_len) +{ + if (!s->ops->flush) { + *out_str = NULL; + *out_len = 0; + return SUCCESS; + } + return s->ops->flush(s, out_str, out_len); +} + +zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s) +{ + if (!s->ops->done) { + return 0; + } + return s->ops->done(s); +} + +STATUS php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *out_len) +{ + if (!s->ops->finish) { + *out_str = NULL; + *out_len = 0; + return SUCCESS; + } + return s->ops->finish(s, out_str, out_len); +} + +void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s) +{ + if (s->ops->dtor) { + s->ops->dtor(s); + } +} + +void php_http_encoding_stream_free(php_http_encoding_stream_t **s) +{ + if (*s) { + if ((*s)->ops->dtor) { + (*s)->ops->dtor(*s); + } + pefree(*s, ((*s)->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + *s = NULL; + } +} + +struct dechunk_ctx { + php_http_buffer_t buffer; + ulong hexlen; + unsigned zeroed:1; +}; + +static php_http_encoding_stream_t *deflate_init(php_http_encoding_stream_t *s) +{ + int status, level, wbits, strategy, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT); + z_streamp ctx = pecalloc(1, sizeof(z_stream), p); + TSRMLS_FETCH_FROM_CTX(s->ts); + + PHP_HTTP_DEFLATE_LEVEL_SET(s->flags, level); + PHP_HTTP_DEFLATE_WBITS_SET(s->flags, wbits); + PHP_HTTP_DEFLATE_STRATEGY_SET(s->flags, strategy); + + if (Z_OK == (status = deflateInit2(ctx, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy))) { + if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) { + s->ctx = ctx; + return s; + } + deflateEnd(ctx); + status = Z_MEM_ERROR; + } + pefree(ctx, p); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize deflate encoding stream: %s", zError(status)); + return NULL; +} + +static php_http_encoding_stream_t *inflate_init(php_http_encoding_stream_t *s) +{ + int status, wbits, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT); + z_streamp ctx = pecalloc(1, sizeof(z_stream), p); + TSRMLS_FETCH_FROM_CTX(s->ts); + + PHP_HTTP_INFLATE_WBITS_SET(s->flags, wbits); + + if (Z_OK == (status = inflateInit2(ctx, wbits))) { + if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) { + s->ctx = ctx; + return s; + } + inflateEnd(ctx); + status = Z_MEM_ERROR; + } + pefree(ctx, p); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize inflate stream: %s", zError(status)); + return NULL; +} + +static php_http_encoding_stream_t *dechunk_init(php_http_encoding_stream_t *s) +{ + struct dechunk_ctx *ctx = pecalloc(1, sizeof(*ctx), (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + + if (!php_http_buffer_init_ex(&ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT) ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) { + return NULL; + } + + ctx->hexlen = 0; + ctx->zeroed = 0; + s->ctx = ctx; + + return s; +} + +static php_http_encoding_stream_t *deflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to) +{ + int status, p = to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT; + z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p); + TSRMLS_FETCH_FROM_CTX(from->ts); + + if (Z_OK == (status = deflateCopy(to_ctx, from_ctx))) { + if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) { + php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used); + to->ctx = to_ctx; + return to; + } + deflateEnd(to_ctx); + status = Z_MEM_ERROR; + } + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to copy deflate encoding stream: %s", zError(status)); + return NULL; +} + +static php_http_encoding_stream_t *inflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to) +{ + int status, p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT; + z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p); + TSRMLS_FETCH_FROM_CTX(from->ts); + + if (Z_OK == (status = inflateCopy(to_ctx, from_ctx))) { + if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) { + php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used); + to->ctx = to_ctx; + return to; + } + inflateEnd(to_ctx); + status = Z_MEM_ERROR; + } + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to copy inflate encoding stream: %s", zError(status)); + return NULL; +} + +static php_http_encoding_stream_t *dechunk_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to) +{ + int p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT; + struct dechunk_ctx *from_ctx = from->ctx, *to_ctx = pemalloc(sizeof(*to_ctx), p); + TSRMLS_FETCH_FROM_CTX(from->ts); + + if (php_http_buffer_init_ex(&to_ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) { + to_ctx->hexlen = from_ctx->hexlen; + to_ctx->zeroed = from_ctx->zeroed; + php_http_buffer_append(&to_ctx->buffer, from_ctx->buffer.data, from_ctx->buffer.used); + to->ctx = to_ctx; + return to; + } + pefree(to_ctx, p); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to copy inflate encoding stream: out of memory"); + return NULL; +} + +static STATUS deflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len) +{ + int status; + z_streamp ctx = s->ctx; + TSRMLS_FETCH_FROM_CTX(s->ts); + + /* append input to our buffer */ + php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len); + + ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data; + ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used; + + /* deflate */ + *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len); + *encoded = emalloc(*encoded_len); + ctx->avail_out = *encoded_len; + ctx->next_out = (Bytef *) *encoded; + + switch (status = deflate(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags))) { + case Z_OK: + case Z_STREAM_END: + /* cut processed chunk off the buffer */ + if (ctx->avail_in) { + php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in); + } else { + php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque)); + } + + /* size buffer down to actual size */ + *encoded_len -= ctx->avail_out; + *encoded = erealloc(*encoded, *encoded_len + 1); + (*encoded)[*encoded_len] = '\0'; + return SUCCESS; + } + + STR_SET(*encoded, NULL); + *encoded_len = 0; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to update deflate stream: %s", zError(status)); + return FAILURE; +} + +static STATUS inflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len) +{ + int status; + z_streamp ctx = s->ctx; + TSRMLS_FETCH_FROM_CTX(s->ts); + + /* append input to buffer */ + php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len); + +retry_raw_inflate: + ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data; + ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used; + + switch (status = php_http_inflate_rounds(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags), decoded, decoded_len)) { + case Z_OK: + case Z_STREAM_END: + /* cut off */ + if (ctx->avail_in) { + php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in); + } else { + php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque)); + } + return SUCCESS; + + case Z_DATA_ERROR: + /* raw deflated data ? */ + if (!(s->flags & PHP_HTTP_INFLATE_TYPE_RAW) && !ctx->total_out) { + inflateEnd(ctx); + s->flags |= PHP_HTTP_INFLATE_TYPE_RAW; + inflateInit2(ctx, PHP_HTTP_WINDOW_BITS_RAW); + goto retry_raw_inflate; + } + break; + } + + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to update inflate stream: %s", zError(status)); + return FAILURE; +} + +static STATUS dechunk_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len) +{ + php_http_buffer_t tmp; + struct dechunk_ctx *ctx = s->ctx; + TSRMLS_FETCH_FROM_CTX(s->ts); + + if (ctx->zeroed) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dechunk encoding stream has already reached the end of chunked input"); + return FAILURE; + } + if ((PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(&ctx->buffer, data, data_len)) || !php_http_buffer_fix(&ctx->buffer)) { + /* OOM */ + return FAILURE; + } + + *decoded = NULL; + *decoded_len = 0; + + php_http_buffer_init(&tmp); + + /* we have data in our buffer */ + while (ctx->buffer.used) { + + /* we already know the size of the chunk and are waiting for data */ + if (ctx->hexlen) { + + /* not enough data buffered */ + if (ctx->buffer.used < ctx->hexlen) { + + /* flush anyway? */ + if (s->flags & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) { + /* flush all data (should only be chunk data) */ + php_http_buffer_append(&tmp, ctx->buffer.data, ctx->buffer.used); + /* waiting for less data now */ + ctx->hexlen -= ctx->buffer.used; + /* no more buffered data */ + php_http_buffer_reset(&ctx->buffer); + /* break */ + } + + /* we have too less data and don't need to flush */ + else { + break; + } + } + + /* we seem to have all data of the chunk */ + else { + php_http_buffer_append(&tmp, ctx->buffer.data, ctx->hexlen); + /* remove outgoing data from the buffer */ + php_http_buffer_cut(&ctx->buffer, 0, ctx->hexlen); + /* reset hexlen */ + ctx->hexlen = 0; + /* continue */ + } + } + + /* we don't know the length of the chunk yet */ + else { + size_t off = 0; + + /* ignore preceeding CRLFs (too loose?) */ + while (off < ctx->buffer.used && ( + ctx->buffer.data[off] == '\n' || + ctx->buffer.data[off] == '\r')) { + ++off; + } + if (off) { + php_http_buffer_cut(&ctx->buffer, 0, off); + } + + /* still data there? */ + if (ctx->buffer.used) { + int eollen; + const char *eolstr; + + /* we need eol, so we can be sure we have all hex digits */ + php_http_buffer_fix(&ctx->buffer); + if ((eolstr = php_http_locate_bin_eol(ctx->buffer.data, ctx->buffer.used, &eollen))) { + char *stop = NULL; + + /* read in chunk size */ + ctx->hexlen = strtoul(ctx->buffer.data, &stop, 16); + + /* if strtoul() stops at the beginning of the buffered data + there's something oddly wrong, i.e. bad input */ + if (stop == ctx->buffer.data) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse chunk len from '%.*s'", (int) MIN(16, ctx->buffer.used), ctx->buffer.data); + php_http_buffer_dtor(&tmp); + return FAILURE; + } + + /* cut out */ + php_http_buffer_cut(&ctx->buffer, 0, eolstr + eollen - ctx->buffer.data); + /* buffer->hexlen is 0 now or contains the size of the next chunk */ + if (!ctx->hexlen) { + size_t off = 0; + + /* ignore following CRLFs (too loose?) */ + while (off < ctx->buffer.used && ( + ctx->buffer.data[off] == '\n' || + ctx->buffer.data[off] == '\r')) { + ++off; + } + if (off) { + php_http_buffer_cut(&ctx->buffer, 0, off); + } + + ctx->zeroed = 1; + break; + } + /* continue */ + } else { + /* we have not enough data buffered to read in chunk size */ + break; + } + } + /* break */ + } + } + + php_http_buffer_fix(&tmp); + *decoded = tmp.data; + *decoded_len = tmp.used; + + return SUCCESS; +} + +static STATUS deflate_flush(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len) +{ + int status; + z_streamp ctx = s->ctx; + TSRMLS_FETCH_FROM_CTX(s->ts); + + *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE; + *encoded = emalloc(*encoded_len); + + ctx->avail_in = 0; + ctx->next_in = NULL; + ctx->avail_out = *encoded_len; + ctx->next_out = (Bytef *) *encoded; + + switch (status = deflate(ctx, Z_FULL_FLUSH)) { + case Z_OK: + case Z_STREAM_END: + *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE - ctx->avail_out; + *encoded = erealloc(*encoded, *encoded_len + 1); + (*encoded)[*encoded_len] = '\0'; + return SUCCESS; + } + + STR_SET(*encoded, NULL); + *encoded_len = 0; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to flush deflate stream: %s", zError(status)); + return FAILURE; +} + +static STATUS dechunk_flush(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len) +{ + struct dechunk_ctx *ctx = s->ctx; + + if (ctx->hexlen) { + /* flush all data (should only be chunk data) */ + php_http_buffer_fix(&ctx->buffer); + php_http_buffer_data(&ctx->buffer, decoded, decoded_len); + /* waiting for less data now */ + ctx->hexlen -= ctx->buffer.used; + /* no more buffered data */ + php_http_buffer_reset(&ctx->buffer); + } else { + *decoded = NULL; + *decoded_len = 0; + } + + return SUCCESS; +} + +static STATUS deflate_finish(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len) +{ + int status; + z_streamp ctx = s->ctx; + TSRMLS_FETCH_FROM_CTX(s->ts); + + *encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE; + *encoded = emalloc(*encoded_len); + + /* deflate remaining input */ + ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data; + ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used; + + ctx->avail_out = *encoded_len; + ctx->next_out = (Bytef *) *encoded; + + do { + status = deflate(ctx, Z_FINISH); + } while (Z_OK == status); + + if (Z_STREAM_END == status) { + /* cut processed input off */ + php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in); + + /* size down */ + *encoded_len -= ctx->avail_out; + *encoded = erealloc(*encoded, *encoded_len + 1); + (*encoded)[*encoded_len] = '\0'; + return SUCCESS; + } + + STR_SET(*encoded, NULL); + *encoded_len = 0; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to finish deflate stream: %s", zError(status)); + return FAILURE; +} + +static STATUS inflate_finish(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len) +{ + int status; + z_streamp ctx = s->ctx; + TSRMLS_FETCH_FROM_CTX(s->ts); + + if (!PHP_HTTP_BUFFER(ctx->opaque)->used) { + *decoded = NULL; + *decoded_len = 0; + return SUCCESS; + } + + *decoded_len = (PHP_HTTP_BUFFER(ctx->opaque)->used + 1) * PHP_HTTP_INFLATE_ROUNDS; + *decoded = emalloc(*decoded_len); + + /* inflate remaining input */ + ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data; + ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used; + + ctx->avail_out = *decoded_len; + ctx->next_out = (Bytef *) *decoded; + + if (Z_STREAM_END == (status = inflate(ctx, Z_FINISH))) { + /* cut processed input off */ + php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in); + + /* size down */ + *decoded_len -= ctx->avail_out; + *decoded = erealloc(*decoded, *decoded_len + 1); + (*decoded)[*decoded_len] = '\0'; + return SUCCESS; + } + + STR_SET(*decoded, NULL); + *decoded_len = 0; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to finish inflate stream: %s", zError(status)); + return FAILURE; +} + +static zend_bool deflate_done(php_http_encoding_stream_t *s) +{ + z_streamp ctx = s->ctx; + return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used; +} + +static zend_bool inflate_done(php_http_encoding_stream_t *s) +{ + z_streamp ctx = s->ctx; + return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used; +} + +static zend_bool dechunk_done(php_http_encoding_stream_t *s) +{ + return ((struct dechunk_ctx *) s->ctx)->zeroed; +} + +static void deflate_dtor(php_http_encoding_stream_t *s) +{ + if (s->ctx) { + z_streamp ctx = s->ctx; + + if (ctx->opaque) { + php_http_buffer_free((php_http_buffer_t **) &ctx->opaque); + } + deflateEnd(ctx); + pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + s->ctx = NULL; + } +} + +static void inflate_dtor(php_http_encoding_stream_t *s) +{ + if (s->ctx) { + z_streamp ctx = s->ctx; + + if (ctx->opaque) { + php_http_buffer_free((php_http_buffer_t **) &ctx->opaque); + } + inflateEnd(ctx); + pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + s->ctx = NULL; + } +} + +static void dechunk_dtor(php_http_encoding_stream_t *s) +{ + if (s->ctx) { + struct dechunk_ctx *ctx = s->ctx; + + php_http_buffer_dtor(&ctx->buffer); + pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + s->ctx = NULL; + } +} + +static php_http_encoding_stream_ops_t php_http_encoding_deflate_ops = { + deflate_init, + deflate_copy, + deflate_update, + deflate_flush, + deflate_done, + deflate_finish, + deflate_dtor +}; + +php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void) +{ + return &php_http_encoding_deflate_ops; +} + +static php_http_encoding_stream_ops_t php_http_encoding_inflate_ops = { + inflate_init, + inflate_copy, + inflate_update, + NULL, + inflate_done, + inflate_finish, + inflate_dtor +}; + +php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void) +{ + return &php_http_encoding_inflate_ops; +} + +static php_http_encoding_stream_ops_t php_http_encoding_dechunk_ops = { + dechunk_init, + dechunk_copy, + dechunk_update, + dechunk_flush, + dechunk_done, + NULL, + dechunk_dtor +}; + +php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void) +{ + return &php_http_encoding_dechunk_ops; +} + +static zend_object_handlers php_http_encoding_stream_object_handlers; + +zend_object_value php_http_encoding_stream_object_new(zend_class_entry *ce TSRMLS_DC) +{ + return php_http_encoding_stream_object_new_ex(ce, NULL, NULL TSRMLS_CC); +} + +zend_object_value php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s, php_http_encoding_stream_object_t **ptr TSRMLS_DC) +{ + php_http_encoding_stream_object_t *o; + + o = ecalloc(1, sizeof(*o)); + zend_object_std_init((zend_object *) o, ce TSRMLS_CC); + object_properties_init((zend_object *) o, ce); + + if (ptr) { + *ptr = o; + } + + if (s) { + o->stream = s; + } + + o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_encoding_stream_object_free, NULL TSRMLS_CC); + o->zv.handlers = &php_http_encoding_stream_object_handlers; + + return o->zv; +} + +zend_object_value php_http_encoding_stream_object_clone(zval *this_ptr TSRMLS_DC) +{ + zend_object_value new_ov; + php_http_encoding_stream_object_t *new_obj = NULL, *old_obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + new_ov = php_http_encoding_stream_object_new_ex(old_obj->zo.ce, php_http_encoding_stream_copy(old_obj->stream, NULL), &new_obj TSRMLS_CC); + zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); + + return new_ov; +} + +void php_http_encoding_stream_object_free(void *object TSRMLS_DC) +{ + php_http_encoding_stream_object_t *o = (php_http_encoding_stream_object_t *) object; + + if (o->stream) { + php_http_encoding_stream_free(&o->stream); + } + zend_object_std_dtor((zend_object *) o TSRMLS_CC); + efree(o); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream___construct, 0, 0, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEncodingStream, __construct) +{ + long flags = 0; + php_http_encoding_stream_object_t *obj; + php_http_encoding_stream_ops_t *ops; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (obj->stream) { + php_http_throw(bad_method_call, "http\\Encoding\\Stream cannot be initialized twice", NULL); + return; + } + + if (instanceof_function(obj->zo.ce, php_http_deflate_stream_class_entry TSRMLS_CC)) { + ops = &php_http_encoding_deflate_ops; + } else if (instanceof_function(obj->zo.ce, php_http_inflate_stream_class_entry TSRMLS_CC)) { + ops = &php_http_encoding_inflate_ops; + } else if (instanceof_function(obj->zo.ce, php_http_dechunk_stream_class_entry TSRMLS_CC)) { + ops = &php_http_encoding_dechunk_ops; + } else { + php_http_throw(runtime, "Unknown http\\Encoding\\Stream class '%s'", obj->zo.ce->name); + return; + } + + php_http_expect(obj->stream = php_http_encoding_stream_init(obj->stream, ops, flags TSRMLS_CC), runtime, return); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_update, 0, 0, 1) + ZEND_ARG_INFO(0, data) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEncodingStream, update) +{ + int data_len; + char *data_str; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len)) { + php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (obj->stream) { + size_t encoded_len; + char *encoded_str; + + if (SUCCESS == php_http_encoding_stream_update(obj->stream, data_str, data_len, &encoded_str, &encoded_len)) { + RETURN_STRINGL(encoded_str, encoded_len, 0); + } + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_flush, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEncodingStream, flush) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (obj->stream) { + char *encoded_str; + size_t encoded_len; + + if (SUCCESS == php_http_encoding_stream_flush(obj->stream, &encoded_str, &encoded_len)) { + if (encoded_str) { + RETURN_STRINGL(encoded_str, encoded_len, 0); + } else { + RETURN_EMPTY_STRING(); + } + } + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_done, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEncodingStream, done) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (obj->stream) { + RETURN_BOOL(php_http_encoding_stream_done(obj->stream)); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_finish, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEncodingStream, finish) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_encoding_stream_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (obj->stream) { + char *encoded_str; + size_t encoded_len; + + if (SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len)) { + if (SUCCESS == php_http_encoding_stream_reset(&obj->stream)) { + if (encoded_str) { + RETURN_STRINGL(encoded_str, encoded_len, 0); + } else { + RETURN_EMPTY_STRING(); + } + } else { + STR_FREE(encoded_str); + } + } + } + } +} + +static zend_function_entry php_http_encoding_stream_methods[] = { + PHP_ME(HttpEncodingStream, __construct, ai_HttpEncodingStream___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpEncodingStream, update, ai_HttpEncodingStream_update, ZEND_ACC_PUBLIC) + PHP_ME(HttpEncodingStream, flush, ai_HttpEncodingStream_flush, ZEND_ACC_PUBLIC) + PHP_ME(HttpEncodingStream, done, ai_HttpEncodingStream_done, ZEND_ACC_PUBLIC) + PHP_ME(HttpEncodingStream, finish, ai_HttpEncodingStream_finish, ZEND_ACC_PUBLIC) + EMPTY_FUNCTION_ENTRY +}; + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpDeflateStream_encode, 0, 0, 1) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpDeflateStream, encode) +{ + char *str; + int len; + long flags = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &len, &flags)) { + char *enc_str; + size_t enc_len; + + if (SUCCESS == php_http_encoding_deflate(flags, str, len, &enc_str, &enc_len TSRMLS_CC)) { + RETURN_STRINGL(enc_str, enc_len, 0); + } + } + RETURN_FALSE; +} + +static zend_function_entry php_http_deflate_stream_methods[] = { + PHP_ME(HttpDeflateStream, encode, ai_HttpDeflateStream_encode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + EMPTY_FUNCTION_ENTRY +}; + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpInflateStream_decode, 0, 0, 1) + ZEND_ARG_INFO(0, data) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpInflateStream, decode) +{ + char *str; + int len; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) { + char *enc_str; + size_t enc_len; + + if (SUCCESS == php_http_encoding_inflate(str, len, &enc_str, &enc_len TSRMLS_CC)) { + RETURN_STRINGL(enc_str, enc_len, 0); + } + } + RETURN_FALSE; +} + +static zend_function_entry php_http_inflate_stream_methods[] = { + PHP_ME(HttpInflateStream, decode, ai_HttpInflateStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + EMPTY_FUNCTION_ENTRY +}; + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpDechunkStream_decode, 0, 0, 1) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(1, decoded_len) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpDechunkStream, decode) +{ + char *str; + int len; + zval *zlen = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!", &str, &len, &zlen)) { + const char *end_ptr; + char *enc_str; + size_t enc_len; + + if ((end_ptr = php_http_encoding_dechunk(str, len, &enc_str, &enc_len TSRMLS_CC))) { + if (zlen) { + zval_dtor(zlen); + ZVAL_LONG(zlen, str + len - end_ptr); + } + RETURN_STRINGL(enc_str, enc_len, 0); + } + } + RETURN_FALSE; +} + +static zend_function_entry php_http_dechunk_stream_methods[] = { + PHP_ME(HttpDechunkStream, decode, ai_HttpDechunkStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_encoding_stream_class_entry; +zend_class_entry *php_http_deflate_stream_class_entry; +zend_class_entry *php_http_inflate_stream_class_entry; +zend_class_entry *php_http_dechunk_stream_class_entry; + +PHP_MINIT_FUNCTION(http_encoding) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http\\Encoding", "Stream", php_http_encoding_stream_methods); + php_http_encoding_stream_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + php_http_encoding_stream_class_entry->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; + php_http_encoding_stream_class_entry->create_object = php_http_encoding_stream_object_new; + memcpy(&php_http_encoding_stream_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + php_http_encoding_stream_object_handlers.clone_obj = php_http_encoding_stream_object_clone; + + zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_NONE"), PHP_HTTP_ENCODING_STREAM_FLUSH_NONE TSRMLS_CC); + zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC TSRMLS_CC); + zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL TSRMLS_CC); + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Deflate", php_http_deflate_stream_methods); + php_http_deflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry, NULL TSRMLS_CC); + + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_GZIP"), PHP_HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_ZLIB"), PHP_HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_RAW"), PHP_HTTP_DEFLATE_TYPE_RAW TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_DEFLATE_LEVEL_DEF TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_DEFLATE_LEVEL_MIN TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_DEFLATE_LEVEL_MAX TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_DEF"), PHP_HTTP_DEFLATE_STRATEGY_DEF TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FILT"), PHP_HTTP_DEFLATE_STRATEGY_FILT TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_HUFF"), PHP_HTTP_DEFLATE_STRATEGY_HUFF TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_RLE"), PHP_HTTP_DEFLATE_STRATEGY_RLE TSRMLS_CC); + zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FIXED"), PHP_HTTP_DEFLATE_STRATEGY_FIXED TSRMLS_CC); + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Inflate", php_http_inflate_stream_methods); + php_http_inflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry, NULL TSRMLS_CC); + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Dechunk", php_http_dechunk_stream_methods); + php_http_dechunk_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry, NULL TSRMLS_CC); + + return SUCCESS; +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_encoding.h b/php_http_encoding.h new file mode 100644 index 0000000..decc585 --- /dev/null +++ b/php_http_encoding.h @@ -0,0 +1,197 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_ENCODING_H +#define PHP_HTTP_ENCODING_H + +#include + +extern PHP_MINIT_FUNCTION(http_encoding); +extern PHP_RINIT_FUNCTION(http_encoding); +extern PHP_RSHUTDOWN_FUNCTION(http_encoding); + +#define PHP_HTTP_INFLATE_ROUNDS 100 + +#define PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(S) \ + (((size_t) ((double) S * (double) 1.015)) + 10 + 8 + 4 + 1) +#define PHP_HTTP_INFLATE_BUFFER_SIZE_GUESS(S) \ + (((S) + 1) << 3) +#define PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(S) \ + ((S) += (S) >> (3)) + +#define PHP_HTTP_DEFLATE_BUFFER_SIZE 0x8000 +#define PHP_HTTP_INFLATE_BUFFER_SIZE 0x1000 + +#define PHP_HTTP_DEFLATE_LEVEL_DEF 0x00000000 +#define PHP_HTTP_DEFLATE_LEVEL_MIN 0x00000001 +#define PHP_HTTP_DEFLATE_LEVEL_MAX 0x00000009 +#define PHP_HTTP_DEFLATE_TYPE_ZLIB 0x00000000 +#define PHP_HTTP_DEFLATE_TYPE_GZIP 0x00000010 +#define PHP_HTTP_DEFLATE_TYPE_RAW 0x00000020 +#define PHP_HTTP_DEFLATE_STRATEGY_DEF 0x00000000 +#define PHP_HTTP_DEFLATE_STRATEGY_FILT 0x00000100 +#define PHP_HTTP_DEFLATE_STRATEGY_HUFF 0x00000200 +#define PHP_HTTP_DEFLATE_STRATEGY_RLE 0x00000300 +#define PHP_HTTP_DEFLATE_STRATEGY_FIXED 0x00000400 + +#define PHP_HTTP_DEFLATE_LEVEL_SET(flags, level) \ + switch (flags & 0xf) \ + { \ + default: \ + if ((flags & 0xf) < 10) { \ + level = flags & 0xf; \ + break; \ + } \ + case PHP_HTTP_DEFLATE_LEVEL_DEF: \ + level = Z_DEFAULT_COMPRESSION; \ + break; \ + } + +#define PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits) \ + switch (flags & 0xf0) \ + { \ + case PHP_HTTP_DEFLATE_TYPE_GZIP: \ + wbits = PHP_HTTP_WINDOW_BITS_GZIP; \ + break; \ + case PHP_HTTP_DEFLATE_TYPE_RAW: \ + wbits = PHP_HTTP_WINDOW_BITS_RAW; \ + break; \ + default: \ + wbits = PHP_HTTP_WINDOW_BITS_ZLIB; \ + break; \ + } + +#define PHP_HTTP_INFLATE_WBITS_SET(flags, wbits) \ + if (flags & PHP_HTTP_INFLATE_TYPE_RAW) { \ + wbits = PHP_HTTP_WINDOW_BITS_RAW; \ +} else { \ + wbits = PHP_HTTP_WINDOW_BITS_ANY; \ +} + +#define PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \ + switch (flags & 0xf00) \ + { \ + case PHP_HTTP_DEFLATE_STRATEGY_FILT: \ + strategy = Z_FILTERED; \ + break; \ + case PHP_HTTP_DEFLATE_STRATEGY_HUFF: \ + strategy = Z_HUFFMAN_ONLY; \ + break; \ + case PHP_HTTP_DEFLATE_STRATEGY_RLE: \ + strategy = Z_RLE; \ + break; \ + case PHP_HTTP_DEFLATE_STRATEGY_FIXED: \ + strategy = Z_FIXED; \ + break; \ + default: \ + strategy = Z_DEFAULT_STRATEGY; \ + break; \ + } + +#define PHP_HTTP_WINDOW_BITS_ZLIB 0x0000000f +#define PHP_HTTP_WINDOW_BITS_GZIP 0x0000001f +#define PHP_HTTP_WINDOW_BITS_ANY 0x0000002f +#define PHP_HTTP_WINDOW_BITS_RAW -0x000000f + +#ifndef Z_FIXED +/* Z_FIXED does not exist prior 1.2.2.2 */ +# define Z_FIXED 0 +#endif + +#define PHP_HTTP_INFLATE_TYPE_ZLIB 0x00000000 +#define PHP_HTTP_INFLATE_TYPE_GZIP 0x00000000 +#define PHP_HTTP_INFLATE_TYPE_RAW 0x00000001 + +#define PHP_HTTP_ENCODING_STREAM_FLUSH_NONE 0x00000000 +#define PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC 0x00100000 +#define PHP_HTTP_ENCODING_STREAM_FLUSH_FULL 0x00200000 + +#define PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(f) \ + (((f) & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) ? Z_FULL_FLUSH : \ + (((f) & PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC) ? Z_SYNC_FLUSH : Z_NO_FLUSH)) + +#define PHP_HTTP_ENCODING_STREAM_PERSISTENT 0x01000000 + +typedef struct php_http_encoding_stream php_http_encoding_stream_t; + +typedef php_http_encoding_stream_t *(*php_http_encoding_stream_init_func_t)(php_http_encoding_stream_t *s); +typedef php_http_encoding_stream_t *(*php_http_encoding_stream_copy_func_t)(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to); +typedef STATUS (*php_http_encoding_stream_update_func_t)(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len); +typedef STATUS (*php_http_encoding_stream_flush_func_t)(php_http_encoding_stream_t *s, char **out_str, size_t *out_len); +typedef zend_bool (*php_http_encoding_stream_done_func_t)(php_http_encoding_stream_t *s); +typedef STATUS (*php_http_encoding_stream_finish_func_t)(php_http_encoding_stream_t *s, char **out_str, size_t *out_len); +typedef void (*php_http_encoding_stream_dtor_func_t)(php_http_encoding_stream_t *s); + +typedef struct php_http_encoding_stream_ops { + php_http_encoding_stream_init_func_t init; + php_http_encoding_stream_copy_func_t copy; + php_http_encoding_stream_update_func_t update; + php_http_encoding_stream_flush_func_t flush; + php_http_encoding_stream_done_func_t done; + php_http_encoding_stream_finish_func_t finish; + php_http_encoding_stream_dtor_func_t dtor; +} php_http_encoding_stream_ops_t; + +struct php_http_encoding_stream { + unsigned flags; + void *ctx; + php_http_encoding_stream_ops_t *ops; +#ifdef ZTS + void ***ts; +#endif +}; + +PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void); +PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void); +PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void); + +PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags TSRMLS_DC); +PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to); +PHP_HTTP_API STATUS php_http_encoding_stream_reset(php_http_encoding_stream_t **s); +PHP_HTTP_API STATUS php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len); +PHP_HTTP_API STATUS php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *len); +PHP_HTTP_API zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s); +PHP_HTTP_API STATUS php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *len); +PHP_HTTP_API void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s); +PHP_HTTP_API void php_http_encoding_stream_free(php_http_encoding_stream_t **s); + +PHP_HTTP_API const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC); +PHP_HTTP_API STATUS php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len TSRMLS_DC); +PHP_HTTP_API STATUS php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len TSRMLS_DC); + +typedef struct php_http_encoding_stream_object { + zend_object zo; + zend_object_value zv; + php_http_encoding_stream_t *stream; +} php_http_encoding_stream_object_t; + +PHP_HTTP_API zend_class_entry *php_http_encoding_stream_class_entry; + +zend_object_value php_http_encoding_stream_object_new(zend_class_entry *ce TSRMLS_DC); +zend_object_value php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s, php_http_encoding_stream_object_t **ptr TSRMLS_DC); +zend_object_value php_http_encoding_stream_object_clone(zval *object TSRMLS_DC); +void php_http_encoding_stream_object_free(void *object TSRMLS_DC); + +PHP_HTTP_API zend_class_entry *php_http_deflate_stream_class_entry; +PHP_HTTP_API zend_class_entry *php_http_inflate_stream_class_entry; +PHP_HTTP_API zend_class_entry *php_http_dechunk_stream_class_entry; + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_encoding_api.h b/php_http_encoding_api.h deleted file mode 100644 index ca4ac8d..0000000 --- a/php_http_encoding_api.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_ENCODING_API_H -#define PHP_HTTP_ENCODING_API_H - -#define http_encoding_dechunk(e, el, d, dl) _http_encoding_dechunk((e), (el), (d), (dl) TSRMLS_CC) -PHP_HTTP_API const char *_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC); - -#define http_encoding_response_start(cl, i) _http_encoding_response_start((cl), (i) TSRMLS_CC) -PHP_HTTP_API int _http_encoding_response_start(size_t content_length, zend_bool ignore_http_ohandler TSRMLS_DC); - -#ifdef HTTP_HAVE_ZLIB - -extern PHP_MINIT_FUNCTION(http_encoding); -extern PHP_RINIT_FUNCTION(http_encoding); -extern PHP_RSHUTDOWN_FUNCTION(http_encoding); - -typedef enum _http_encoding_type_t { - HTTP_ENCODING_NONE, - HTTP_ENCODING_GZIP, - HTTP_ENCODING_DEFLATE, -} http_encoding_type; - -#define HTTP_INFLATE_ROUNDS 100 - -#define HTTP_DEFLATE_BUFFER_SIZE_GUESS(S) \ - (((size_t) ((double) S * (double) 1.015)) + 10 + 8 + 4 + 1) -#define HTTP_INFLATE_BUFFER_SIZE_GUESS(S) \ - (((S) + 1) << 3) -#define HTTP_INFLATE_BUFFER_SIZE_ALIGN(S) \ - ((S) += (S) >> (3)) - -#define HTTP_DEFLATE_BUFFER_SIZE 0x8000 -#define HTTP_INFLATE_BUFFER_SIZE 0x1000 - -#define HTTP_DEFLATE_LEVEL_DEF 0x00000000 -#define HTTP_DEFLATE_LEVEL_MIN 0x00000001 -#define HTTP_DEFLATE_LEVEL_MAX 0x00000009 -#define HTTP_DEFLATE_TYPE_ZLIB 0x00000000 -#define HTTP_DEFLATE_TYPE_GZIP 0x00000010 -#define HTTP_DEFLATE_TYPE_RAW 0x00000020 -#define HTTP_DEFLATE_STRATEGY_DEF 0x00000000 -#define HTTP_DEFLATE_STRATEGY_FILT 0x00000100 -#define HTTP_DEFLATE_STRATEGY_HUFF 0x00000200 -#define HTTP_DEFLATE_STRATEGY_RLE 0x00000300 -#define HTTP_DEFLATE_STRATEGY_FIXED 0x00000400 - -#define HTTP_DEFLATE_LEVEL_SET(flags, level) \ - switch (flags & 0xf) \ - { \ - default: \ - if ((flags & 0xf) < 10) { \ - level = flags & 0xf; \ - break; \ - } \ - case HTTP_DEFLATE_LEVEL_DEF: \ - level = Z_DEFAULT_COMPRESSION; \ - break; \ - } - -#define HTTP_DEFLATE_WBITS_SET(flags, wbits) \ - switch (flags & 0xf0) \ - { \ - case HTTP_DEFLATE_TYPE_GZIP: \ - wbits = HTTP_WINDOW_BITS_GZIP; \ - break; \ - case HTTP_DEFLATE_TYPE_RAW: \ - wbits = HTTP_WINDOW_BITS_RAW; \ - break; \ - default: \ - wbits = HTTP_WINDOW_BITS_ZLIB; \ - break; \ - } - -#define HTTP_INFLATE_WBITS_SET(flags, wbits) \ - if (flags & HTTP_INFLATE_TYPE_RAW) { \ - wbits = HTTP_WINDOW_BITS_RAW; \ -} else { \ - wbits = HTTP_WINDOW_BITS_ANY; \ -} - -#define HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \ - switch (flags & 0xf00) \ - { \ - case HTTP_DEFLATE_STRATEGY_FILT: \ - strategy = Z_FILTERED; \ - break; \ - case HTTP_DEFLATE_STRATEGY_HUFF: \ - strategy = Z_HUFFMAN_ONLY; \ - break; \ - case HTTP_DEFLATE_STRATEGY_RLE: \ - strategy = Z_RLE; \ - break; \ - case HTTP_DEFLATE_STRATEGY_FIXED: \ - strategy = Z_FIXED; \ - break; \ - default: \ - strategy = Z_DEFAULT_STRATEGY; \ - break; \ - } - -#define HTTP_WINDOW_BITS_ZLIB 0x0000000f -#define HTTP_WINDOW_BITS_GZIP 0x0000001f -#define HTTP_WINDOW_BITS_ANY 0x0000002f -#define HTTP_WINDOW_BITS_RAW -0x000000f - -#ifndef Z_FIXED -/* Z_FIXED does not exist prior 1.2.2.2 */ -# define Z_FIXED 0 -#endif - -#define HTTP_INFLATE_TYPE_ZLIB 0x00000000 -#define HTTP_INFLATE_TYPE_GZIP 0x00000000 -#define HTTP_INFLATE_TYPE_RAW 0x00000001 - -#define HTTP_ENCODING_STREAM_FLUSH_NONE 0x00000000 -#define HTTP_ENCODING_STREAM_FLUSH_SYNC 0x00100000 -#define HTTP_ENCODING_STREAM_FLUSH_FULL 0x00200000 - -#define HTTP_ENCODING_STREAM_FLUSH_FLAG(f) \ - (((f) & HTTP_ENCODING_STREAM_FLUSH_FULL) ? Z_FULL_FLUSH : \ - (((f) & HTTP_ENCODING_STREAM_FLUSH_SYNC) ? Z_SYNC_FLUSH : Z_NO_FLUSH)) - -#define HTTP_ENCODING_STREAM_PERSISTENT 0x01000000 - -typedef struct _http_encoding_stream_t { - z_stream stream; - int flags; - void *storage; -} http_encoding_stream; - -#define http_encoding_deflate(f, d, dl, r, rl) _http_encoding_deflate((f), (d), (dl), (r), (rl) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); -#define http_encoding_inflate(d, dl, r, rl) _http_encoding_inflate((d), (dl), (r), (rl) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); - -#define http_encoding_deflate_stream_init(s, f) _http_encoding_deflate_stream_init((s), (f) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API http_encoding_stream *_http_encoding_deflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); -#define http_encoding_deflate_stream_update(s, d, dl, e, el) _http_encoding_deflate_stream_update((s), (d), (dl), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_deflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); -#define http_encoding_deflate_stream_flush(s, e, el) _http_encoding_deflate_stream_flush((s), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_deflate_stream_flush(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); -#define http_encoding_deflate_stream_finish(s, e, el) _http_encoding_deflate_stream_finish((s), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_deflate_stream_finish(http_encoding_stream *s, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); -#define http_encoding_deflate_stream_dtor(s) _http_encoding_deflate_stream_dtor((s) TSRMLS_CC) -PHP_HTTP_API void _http_encoding_deflate_stream_dtor(http_encoding_stream *s TSRMLS_DC); -#define http_encoding_deflate_stream_free(s) _http_encoding_deflate_stream_free((s) TSRMLS_CC) -PHP_HTTP_API void _http_encoding_deflate_stream_free(http_encoding_stream **s TSRMLS_DC); - -#define http_encoding_inflate_stream_init(s, f) _http_encoding_inflate_stream_init((s), (f) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API http_encoding_stream *_http_encoding_inflate_stream_init(http_encoding_stream *s, int flags ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); -#define http_encoding_inflate_stream_update(s, d, dl, e, el) _http_encoding_inflate_stream_update((s), (d), (dl), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_inflate_stream_update(http_encoding_stream *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); -#define http_encoding_inflate_stream_flush(s, d, dl) _http_encoding_inflate_stream_flush((s), (d), (dl) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_inflate_stream_flush(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); -#define http_encoding_inflate_stream_finish(s, e, el) _http_encoding_inflate_stream_finish((s), (e), (el) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API STATUS _http_encoding_inflate_stream_finish(http_encoding_stream *s, char **decoded, size_t *decoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); -#define http_encoding_inflate_stream_dtor(s) _http_encoding_inflate_stream_dtor((s) TSRMLS_CC) -PHP_HTTP_API void _http_encoding_inflate_stream_dtor(http_encoding_stream *s TSRMLS_DC); -#define http_encoding_inflate_stream_free(s) _http_encoding_inflate_stream_free((s) TSRMLS_CC) -PHP_HTTP_API void _http_encoding_inflate_stream_free(http_encoding_stream **s TSRMLS_DC); - -#define http_ob_deflatehandler(o, ol, h, hl, m) _http_ob_deflatehandler((o), (ol), (h), (hl), (m) TSRMLS_CC) -extern void _http_ob_deflatehandler(char *, uint, char **, uint *, int TSRMLS_DC); - -#define http_ob_inflatehandler(o, ol, h, hl, m) _http_ob_inflatehandler((o), (ol), (h), (hl), (m) TSRMLS_CC) -extern void _http_ob_inflatehandler(char *, uint, char **, uint *, int TSRMLS_DC); - -#endif /* HTTP_HAVE_ZLIB */ - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/php_http_env.c b/php_http_env.c new file mode 100644 index 0000000..c98701b --- /dev/null +++ b/php_http_env.c @@ -0,0 +1,1023 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" +#include "php_variables.h" + +PHP_RINIT_FUNCTION(http_env) +{ + PHP_HTTP_G->env.request.time = sapi_get_request_time(TSRMLS_C); + + /* populate form data on non-POST requests */ + if (SG(request_info).request_method && strcasecmp(SG(request_info).request_method, "POST") && SG(request_info).content_type && *SG(request_info).content_type) { + uint ct_len = strlen(SG(request_info).content_type); + char *ct_str = estrndup(SG(request_info).content_type, ct_len); + php_http_params_opts_t opts; + HashTable params; + + php_http_params_opts_default_get(&opts); + opts.input.str = ct_str; + opts.input.len = ct_len; + + SG(request_info).content_type_dup = ct_str; + + ZEND_INIT_SYMTABLE(¶ms); + if (php_http_params_parse(¶ms, &opts TSRMLS_CC)) { + char *key_str; + uint key_len; + ulong key_num; + + if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(¶ms, &key_str, &key_len, &key_num, 0, NULL)) { + sapi_post_entry *post_entry = NULL; + + if (SUCCESS == zend_hash_find(&SG(known_post_content_types), key_str, key_len, (void *) &post_entry)) { + zval *files = PG(http_globals)[TRACK_VARS_FILES]; + + if (post_entry) { + SG(request_info).post_entry = post_entry; + + if (post_entry->post_reader) { + post_entry->post_reader(TSRMLS_C); + } + } + + if (sapi_module.default_post_reader) { + sapi_module.default_post_reader(TSRMLS_C); + } + + sapi_handle_post(PG(http_globals)[TRACK_VARS_POST] TSRMLS_CC); + + /* + * the rfc1867 handler is an awkward buddy + */ + if (files != PG(http_globals)[TRACK_VARS_FILES] && PG(http_globals)[TRACK_VARS_FILES]) { + Z_ADDREF_P(PG(http_globals)[TRACK_VARS_FILES]); + zend_hash_update(&EG(symbol_table), "_FILES", sizeof("_FILES"), &PG(http_globals)[TRACK_VARS_FILES], sizeof(zval *), NULL); + if (files) { + zval_ptr_dtor(&files); + } + } + } + } + zend_hash_destroy(¶ms); + } + } + + STR_SET(SG(request_info).content_type_dup, NULL); + + return SUCCESS; +} + +PHP_RSHUTDOWN_FUNCTION(http_env) +{ + if (PHP_HTTP_G->env.request.headers) { + zend_hash_destroy(PHP_HTTP_G->env.request.headers); + FREE_HASHTABLE(PHP_HTTP_G->env.request.headers); + PHP_HTTP_G->env.request.headers = NULL; + } + if (PHP_HTTP_G->env.request.body) { + php_http_message_body_free(&PHP_HTTP_G->env.request.body); + } + + if (PHP_HTTP_G->env.server_var) { + zval_ptr_dtor(&PHP_HTTP_G->env.server_var); + PHP_HTTP_G->env.server_var = NULL; + } + + return SUCCESS; +} + +void php_http_env_get_request_headers(HashTable *headers TSRMLS_DC) +{ + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + zval **hsv, **header; + HashPosition pos; + + if (!PHP_HTTP_G->env.request.headers) { + ALLOC_HASHTABLE(PHP_HTTP_G->env.request.headers); + zend_hash_init(PHP_HTTP_G->env.request.headers, 0, NULL, ZVAL_PTR_DTOR, 0); + + zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC); + + if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv) && Z_TYPE_PP(hsv) == IS_ARRAY) { + FOREACH_KEY(pos, *hsv, key) { + if (key.type == HASH_KEY_IS_STRING && key.len > 6 && *key.str == 'H' && !strncmp(key.str, "HTTP_", 5)) { + key.len -= 5; + key.str = php_http_pretty_key(estrndup(key.str + 5, key.len - 1), key.len - 1, 1, 1); + + zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos); + Z_ADDREF_P(*header); + zend_symtable_update(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL); + + efree(key.str); + } else if (key.type == HASH_KEY_IS_STRING && key.len > 9 && *key.str == 'C' && !strncmp(key.str, "CONTENT_", 8)) { + key.str = php_http_pretty_key(estrndup(key.str, key.len - 1), key.len - 1, 1, 1); + + zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos); + Z_ADDREF_P(*header); + zend_symtable_update(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL); + + efree(key.str); + } + } + } + } + + if (headers) { + zend_hash_copy(headers, PHP_HTTP_G->env.request.headers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + } +} + +char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request TSRMLS_DC) +{ + HashTable *request_headers; + zval **zvalue = NULL; + char *val = NULL, *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); + + if (request) { + request_headers = &request->hdrs; + } else { + php_http_env_get_request_headers(NULL TSRMLS_CC); + request_headers = PHP_HTTP_G->env.request.headers; + } + + if (SUCCESS == zend_symtable_find(request_headers, key, name_len + 1, (void *) &zvalue)) { + zval *zcopy = php_http_ztyp(IS_STRING, *zvalue); + + val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy)); + if (len) { + *len = Z_STRLEN_P(zcopy); + } + zval_ptr_dtor(&zcopy); + } + + efree(key); + + return val; +} + +int php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request TSRMLS_DC) +{ + HashTable *request_headers; + char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); + int got; + + if (request) { + request_headers = &request->hdrs; + } else { + php_http_env_get_request_headers(NULL TSRMLS_CC); + request_headers = PHP_HTTP_G->env.request.headers; + } + got = zend_symtable_exists(request_headers, key, name_len + 1); + efree(key); + + return got; +} + +zval *php_http_env_get_superglobal(const char *key, size_t key_len TSRMLS_DC) +{ + zval **hsv; + + zend_is_auto_global(key, key_len TSRMLS_CC); + + if ((SUCCESS != zend_hash_find(&EG(symbol_table), key, key_len + 1, (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) { + return NULL; + } + + return *hsv; +} + +zval *php_http_env_get_server_var(const char *key, size_t key_len, zend_bool check TSRMLS_DC) +{ + zval *hsv, **var; + char *env; + + /* if available, this is a lot faster than accessing $_SERVER */ + if (sapi_module.getenv) { + if ((!(env = sapi_module.getenv((char *) key, key_len TSRMLS_CC))) || (check && !*env)) { + return NULL; + } + if (PHP_HTTP_G->env.server_var) { + zval_ptr_dtor(&PHP_HTTP_G->env.server_var); + } + MAKE_STD_ZVAL(PHP_HTTP_G->env.server_var); + ZVAL_STRING(PHP_HTTP_G->env.server_var, env, 1); + return PHP_HTTP_G->env.server_var; + } + + if (!(hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER") TSRMLS_CC))) { + return NULL; + } + if ((SUCCESS != zend_symtable_find(Z_ARRVAL_P(hsv), key, key_len + 1, (void *) &var))) { + return NULL; + } + if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) { + return NULL; + } + return *var; +} + +php_http_message_body_t *php_http_env_get_request_body(TSRMLS_D) +{ + if (!PHP_HTTP_G->env.request.body) { + php_stream *s = php_stream_temp_new(); +#if PHP_VERSION_ID >= 50600 + php_stream *input = php_stream_open_wrapper("php://input", "r", 0, NULL); + + /* php://input does not support stat */ + php_stream_copy_to_stream_ex(input, s, -1, NULL); + php_stream_close(input); +#else + if (SG(request_info).post_data || SG(request_info).raw_post_data) { + /* php://input does not support seek() in PHP <= 5.5 */ + if (SG(request_info).raw_post_data) { + php_stream_write(s, SG(request_info).raw_post_data, SG(request_info).raw_post_data_length); + } else { + php_stream_write(s, SG(request_info).post_data, SG(request_info).post_data_length); + } + } else if (sapi_module.read_post && !SG(read_post_bytes)) { + char *buf = emalloc(4096); + int len; + + while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) { + SG(read_post_bytes) += len; + php_stream_write(s, buf, len); + + if (len < 4096) { + break; + } + } + efree(buf); + } +#endif + php_stream_rewind(s); + PHP_HTTP_G->env.request.body = php_http_message_body_init(NULL, s TSRMLS_CC); + } + + return PHP_HTTP_G->env.request.body; +} + +const char *php_http_env_get_request_method(php_http_message_t *request TSRMLS_DC) +{ + const char *m; + + if (PHP_HTTP_MESSAGE_TYPE(REQUEST, request)) { + m = request->http.info.request.method; + } else { + m = SG(request_info).request_method; + } + + return m ? m : "GET"; +} + +php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t length, php_http_message_t *request TSRMLS_DC) +{ + zval *zentry; + char *range, *rp, c; + long begin = -1, end = -1, *ptr; + + if (!(range = php_http_env_get_request_header(ZEND_STRL("Range"), NULL, request TSRMLS_CC))) { + return PHP_HTTP_RANGE_NO; + } + if (strncmp(range, "bytes=", lenof("bytes="))) { + STR_FREE(range); + return PHP_HTTP_RANGE_NO; + } + + rp = range + lenof("bytes="); + ptr = &begin; + + do { + switch (c = *(rp++)) { + case '0': + /* allow 000... - shall we? */ + if (*ptr != -10) { + *ptr *= 10; + } + break; + + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + /* + * If the value of the pointer is already set (non-negative) + * then multiply its value by ten and add the current value, + * else initialise the pointers value with the current value + * -- + * This let us recognize empty fields when validating the + * ranges, i.e. a "-10" for begin and "12345" for the end + * was the following range request: "Range: bytes=0-12345"; + * While a "-1" for begin and "12345" for the end would + * have been: "Range: bytes=-12345". + */ + if (*ptr > 0) { + *ptr *= 10; + *ptr += c - '0'; + } else { + *ptr = c - '0'; + } + break; + + case '-': + ptr = &end; + break; + + case ' ': + break; + + case 0: + case ',': + + if (length) { + /* validate ranges */ + switch (begin) { + /* "0-12345" */ + case -10: + switch (end) { + /* "0-" */ + case -1: + STR_FREE(range); + return PHP_HTTP_RANGE_NO; + + /* "0-0" */ + case -10: + end = 0; + break; + + default: + if (length <= (size_t) end) { + end = length - 1; + } + break; + } + begin = 0; + break; + + /* "-12345" */ + case -1: + /* "-", "-0" */ + if (end == -1 || end == -10) { + STR_FREE(range); + return PHP_HTTP_RANGE_ERR; + } + begin = length - end; + end = length - 1; + break; + + /* "12345-(NNN)" */ + default: + if (length <= (size_t) begin) { + STR_FREE(range); + return PHP_HTTP_RANGE_ERR; + } + switch (end) { + /* "12345-0" */ + case -10: + STR_FREE(range); + return PHP_HTTP_RANGE_ERR; + + /* "12345-" */ + case -1: + end = length - 1; + break; + + /* "12345-67890" */ + default: + if (length <= (size_t) end) { + end = length - 1; + } else if (end < begin) { + STR_FREE(range); + return PHP_HTTP_RANGE_ERR; + } + break; + } + break; + } + } + + MAKE_STD_ZVAL(zentry); + array_init(zentry); + add_index_long(zentry, 0, begin); + add_index_long(zentry, 1, end); + zend_hash_next_index_insert(ranges, &zentry, sizeof(zval *), NULL); + + begin = -1; + end = -1; + ptr = &begin; + + break; + + default: + STR_FREE(range); + return PHP_HTTP_RANGE_NO; + } + } while (c != 0); + + STR_FREE(range); + return PHP_HTTP_RANGE_OK; +} + +static void grab_headers(void *data, void *arg TSRMLS_DC) +{ + php_http_buffer_appendl(PHP_HTTP_BUFFER(arg), ((sapi_header_struct *)data)->header); + php_http_buffer_appends(PHP_HTTP_BUFFER(arg), PHP_HTTP_CRLF); +} + +STATUS php_http_env_get_response_headers(HashTable *headers_ht TSRMLS_DC) +{ + STATUS status; + php_http_buffer_t headers; + + php_http_buffer_init(&headers); + zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_headers, &headers TSRMLS_CC); + php_http_buffer_fix(&headers); + + status = php_http_header_parse(headers.data, headers.used, headers_ht, NULL, NULL TSRMLS_CC); + php_http_buffer_dtor(&headers); + + return status; +} + +char *php_http_env_get_response_header(const char *name_str, size_t name_len TSRMLS_DC) +{ + char *val = NULL; + HashTable headers; + + zend_hash_init(&headers, 0, NULL, ZVAL_PTR_DTOR, 0); + if (SUCCESS == php_http_env_get_response_headers(&headers TSRMLS_CC)) { + zval **zvalue; + char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); + + if (SUCCESS == zend_symtable_find(&headers, key, name_len + 1, (void *) &zvalue)) { + zval *zcopy = php_http_ztyp(IS_STRING, *zvalue); + + val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy)); + zval_ptr_dtor(&zcopy); + } + + efree(key); + } + zend_hash_destroy(&headers); + + return val; +} + +long php_http_env_get_response_code(TSRMLS_D) +{ + long code = SG(sapi_headers).http_response_code; + return code ? code : 200; +} + +STATUS php_http_env_set_response_code(long http_code TSRMLS_DC) +{ + return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) http_code TSRMLS_CC); +} + +STATUS php_http_env_set_response_status_line(long code, php_http_version_t *v TSRMLS_DC) +{ + sapi_header_line h = {NULL, 0, 0}; + STATUS ret; + + h.line_len = spprintf(&h.line, 0, "HTTP/%u.%u %ld %s", v->major, v->minor, code, php_http_env_get_response_status_for_code(code)); + ret = sapi_header_op(SAPI_HEADER_REPLACE, (void *) &h TSRMLS_CC); + efree(h.line); + + return ret; +} + +STATUS php_http_env_set_response_protocol_version(php_http_version_t *v TSRMLS_DC) +{ + return php_http_env_set_response_status_line(php_http_env_get_response_code(TSRMLS_C), v TSRMLS_CC); +} + +STATUS php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace TSRMLS_DC) +{ + sapi_header_line h = {estrndup(header_str, header_len), header_len, http_code}; + STATUS ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC); + efree(h.line); + return ret; +} + +STATUS php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv TSRMLS_DC) +{ + STATUS ret = FAILURE; + sapi_header_line h = {NULL, 0, http_code}; + + h.line_len = vspprintf(&h.line, 0, fmt, argv); + + if (h.line) { + if (h.line_len) { + ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC); + } + efree(h.line); + } + return ret; +} + +STATUS php_http_env_set_response_header_format(long http_code, zend_bool replace TSRMLS_DC, const char *fmt, ...) +{ + STATUS ret; + va_list args; + + va_start(args, fmt); + ret = php_http_env_set_response_header_va(http_code, replace, fmt, args TSRMLS_CC); + va_end(args); + + return ret; +} + +STATUS php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace TSRMLS_DC) +{ + if (!value) { + sapi_header_line h = {(char *) name_str, name_len, http_code}; + + return sapi_header_op(SAPI_HEADER_DELETE, (void *) &h TSRMLS_CC); + } + + if(Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) { + HashPosition pos; + int first = replace; + zval **data_ptr; + + FOREACH_HASH_VAL(pos, HASH_OF(value), data_ptr) { + if (SUCCESS != php_http_env_set_response_header_value(http_code, name_str, name_len, *data_ptr, first TSRMLS_CC)) { + return FAILURE; + } + first = 0; + } + + return SUCCESS; + } else { + zval *data = php_http_ztyp(IS_STRING, value); + + if (!Z_STRLEN_P(data)) { + zval_ptr_dtor(&data); + return php_http_env_set_response_header_value(http_code, name_str, name_len, NULL, replace TSRMLS_CC); + } else { + sapi_header_line h; + STATUS ret; + + if (name_len > INT_MAX) { + name_len = INT_MAX; + } + h.response_code = http_code; + h.line_len = spprintf(&h.line, 0, "%.*s: %.*s", (int) name_len, name_str, Z_STRLEN_P(data), Z_STRVAL_P(data)); + + ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC); + + zval_ptr_dtor(&data); + STR_FREE(h.line); + + return ret; + } + } +} + +static PHP_HTTP_STRLIST(php_http_env_response_status) = + PHP_HTTP_STRLIST_ITEM("Continue") + PHP_HTTP_STRLIST_ITEM("Switching Protocols") + PHP_HTTP_STRLIST_ITEM("Processing") + PHP_HTTP_STRLIST_NEXT + PHP_HTTP_STRLIST_ITEM("OK") + PHP_HTTP_STRLIST_ITEM("Created") + PHP_HTTP_STRLIST_ITEM("Accepted") + PHP_HTTP_STRLIST_ITEM("Non-Authoritative Information") + PHP_HTTP_STRLIST_ITEM("No Content") + PHP_HTTP_STRLIST_ITEM("Reset Content") + PHP_HTTP_STRLIST_ITEM("Partial Content") + PHP_HTTP_STRLIST_ITEM("Multi-Status") + PHP_HTTP_STRLIST_ITEM("Already Reported") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("IM Used") + PHP_HTTP_STRLIST_NEXT + PHP_HTTP_STRLIST_ITEM("Multiple Choices") + PHP_HTTP_STRLIST_ITEM("Moved Permanently") + PHP_HTTP_STRLIST_ITEM("Found") + PHP_HTTP_STRLIST_ITEM("See Other") + PHP_HTTP_STRLIST_ITEM("Not Modified") + PHP_HTTP_STRLIST_ITEM("Use Proxy") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("Temporary Redirect") + PHP_HTTP_STRLIST_ITEM("Permanent Redirect") + PHP_HTTP_STRLIST_NEXT + PHP_HTTP_STRLIST_ITEM("Bad Request") + PHP_HTTP_STRLIST_ITEM("Unauthorized") + PHP_HTTP_STRLIST_ITEM("Payment Required") + PHP_HTTP_STRLIST_ITEM("Forbidden") + PHP_HTTP_STRLIST_ITEM("Not Found") + PHP_HTTP_STRLIST_ITEM("Method Not Allowed") + PHP_HTTP_STRLIST_ITEM("Not Acceptable") + PHP_HTTP_STRLIST_ITEM("Proxy Authentication Required") + PHP_HTTP_STRLIST_ITEM("Request Timeout") + PHP_HTTP_STRLIST_ITEM("Conflict") + PHP_HTTP_STRLIST_ITEM("Gone") + PHP_HTTP_STRLIST_ITEM("Length Required") + PHP_HTTP_STRLIST_ITEM("Precondition Failed") + PHP_HTTP_STRLIST_ITEM("Request Entity Too Large") + PHP_HTTP_STRLIST_ITEM("Request URI Too Long") + PHP_HTTP_STRLIST_ITEM("Unsupported Media Type") + PHP_HTTP_STRLIST_ITEM("Requested Range Not Satisfiable") + PHP_HTTP_STRLIST_ITEM("Expectation Failed") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("Unprocessible Entity") + PHP_HTTP_STRLIST_ITEM("Locked") + PHP_HTTP_STRLIST_ITEM("Failed Dependency") + PHP_HTTP_STRLIST_ITEM("(Reserved)") + PHP_HTTP_STRLIST_ITEM("Upgrade Required") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("Precondition Required") + PHP_HTTP_STRLIST_ITEM("Too Many Requests") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("Request Header Fields Too Large") + PHP_HTTP_STRLIST_NEXT + PHP_HTTP_STRLIST_ITEM("Internal Server Error") + PHP_HTTP_STRLIST_ITEM("Not Implemented") + PHP_HTTP_STRLIST_ITEM("Bad Gateway") + PHP_HTTP_STRLIST_ITEM("Service Unavailable") + PHP_HTTP_STRLIST_ITEM("Gateway Timeout") + PHP_HTTP_STRLIST_ITEM("HTTP Version Not Supported") + PHP_HTTP_STRLIST_ITEM("Variant Also Negotiates") + PHP_HTTP_STRLIST_ITEM("Insufficient Storage") + PHP_HTTP_STRLIST_ITEM("Loop Detected") + PHP_HTTP_STRLIST_ITEM("(Unused)") + PHP_HTTP_STRLIST_ITEM("Not Extended") + PHP_HTTP_STRLIST_ITEM("Network Authentication Required") + PHP_HTTP_STRLIST_STOP +; + +const char *php_http_env_get_response_status_for_code(unsigned code) +{ + return php_http_strlist_find(php_http_env_response_status, 100, code); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestHeader, 0, 0, 0) + ZEND_ARG_INFO(0, header_name) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, getRequestHeader) +{ + char *header_name_str = NULL; + int header_name_len = 0; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) { + return; + } + if (header_name_str && header_name_len) { + size_t header_length; + char *header_value = php_http_env_get_request_header(header_name_str, header_name_len, &header_length, NULL TSRMLS_CC); + + if (header_value) { + RETURN_STRINGL(header_value, header_length, 0); + } + } else { + array_init(return_value); + php_http_env_get_request_headers(Z_ARRVAL_P(return_value) TSRMLS_CC); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestBody, 0, 0, 0) + ZEND_ARG_INFO(0, body_class_name) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, getRequestBody) +{ + zend_object_value ov; + php_http_message_body_t *body; + zend_class_entry *class_entry = php_http_message_body_class_entry; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &class_entry), invalid_arg, return); + + body = php_http_env_get_request_body(TSRMLS_C); + if (SUCCESS == php_http_new(&ov, class_entry, (php_http_new_t) php_http_message_body_object_new_ex, php_http_message_body_class_entry, body, NULL TSRMLS_CC)) { + RETVAL_OBJVAL(ov, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForCode, 0, 0, 1) + ZEND_ARG_INFO(0, code) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, getResponseStatusForCode) +{ + long code; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) { + return; + } + RETURN_STRING(php_http_env_get_response_status_for_code(code), 1); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForAllCodes, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, getResponseStatusForAllCodes) +{ + const char *s; + unsigned c; + php_http_strlist_iterator_t i; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + array_init(return_value); + for ( php_http_strlist_iterator_init(&i, php_http_env_response_status, 100); + *(s = php_http_strlist_iterator_this(&i, &c)); + php_http_strlist_iterator_next(&i) + ) { + add_index_string(return_value, c, s, 1); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseHeader, 0, 0, 0) + ZEND_ARG_INFO(0, header_name) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, getResponseHeader) +{ + char *header_name_str = NULL; + int header_name_len = 0; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) { + return; + } + if (header_name_str && header_name_len) { + char *header_value = php_http_env_get_response_header(header_name_str, header_name_len TSRMLS_CC); + + if (header_value) { + RETURN_STRING(header_value, 0); + } + } else { + array_init(return_value); + php_http_env_get_response_headers(Z_ARRVAL_P(return_value) TSRMLS_CC); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseCode, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, getResponseCode) +{ + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + RETURN_LONG(php_http_env_get_response_code(TSRMLS_C)); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseHeader, 0, 0, 1) + ZEND_ARG_INFO(0, header_name) + ZEND_ARG_INFO(0, header_value) + ZEND_ARG_INFO(0, response_code) + ZEND_ARG_INFO(0, replace_header) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, setResponseHeader) +{ + char *header_name_str; + int header_name_len; + zval *header_value = NULL; + long code = 0; + zend_bool replace_header = 1; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!lb", &header_name_str, &header_name_len, &header_value, &code, &replace_header)) { + return; + } + RETURN_BOOL(SUCCESS == php_http_env_set_response_header_value(code, header_name_str, header_name_len, header_value, replace_header TSRMLS_CC)); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseCode, 0, 0, 1) + ZEND_ARG_INFO(0, code) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, setResponseCode) +{ + long code; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) { + return; + } + RETURN_BOOL(SUCCESS == php_http_env_set_response_code(code TSRMLS_CC)); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateLanguage, 0, 0, 1) + ZEND_ARG_INFO(0, supported) + ZEND_ARG_INFO(1, result_array) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, negotiateLanguage) +{ + HashTable *supported; + zval *rs_array = NULL; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) { + return; + } + if (rs_array) { + zval_dtor(rs_array); + array_init(rs_array); + } + + PHP_HTTP_DO_NEGOTIATE(language, supported, rs_array); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateCharset, 0, 0, 1) + ZEND_ARG_INFO(0, supported) + ZEND_ARG_INFO(1, result_array) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, negotiateCharset) +{ + HashTable *supported; + zval *rs_array = NULL; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) { + return; + } + if (rs_array) { + zval_dtor(rs_array); + array_init(rs_array); + } + PHP_HTTP_DO_NEGOTIATE(charset, supported, rs_array); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateEncoding, 0, 0, 1) + ZEND_ARG_INFO(0, supported) + ZEND_ARG_INFO(1, result_array) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, negotiateEncoding) +{ + HashTable *supported; + zval *rs_array = NULL; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) { + return; + } + if (rs_array) { + zval_dtor(rs_array); + array_init(rs_array); + } + PHP_HTTP_DO_NEGOTIATE(encoding, supported, rs_array); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateContentType, 0, 0, 1) + ZEND_ARG_INFO(0, supported) + ZEND_ARG_INFO(1, result_array) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, negotiateContentType) +{ + HashTable *supported; + zval *rs_array = NULL; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) { + return; + } + if (rs_array) { + zval_dtor(rs_array); + array_init(rs_array); + } + PHP_HTTP_DO_NEGOTIATE(content_type, supported, rs_array); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiate, 0, 0, 2) + ZEND_ARG_INFO(0, params) + ZEND_ARG_INFO(0, supported) + ZEND_ARG_INFO(0, primary_type_separator) + ZEND_ARG_INFO(1, result_array) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnv, negotiate) +{ + HashTable *supported, *rs; + zval *rs_array = NULL; + char *value_str, *sep_str = NULL; + int value_len, sep_len = 0; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sH|s!z", &value_str, &value_len, &supported, &sep_str, &sep_len, &rs_array)) { + return; + } + + + if (rs_array) { + zval_dtor(rs_array); + array_init(rs_array); + } + + if ((rs = php_http_negotiate(value_str, value_len, supported, sep_str, sep_len TSRMLS_CC))) { + PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array); + } else { + PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); + } +} + +static zend_function_entry php_http_env_methods[] = { + PHP_ME(HttpEnv, getRequestHeader, ai_HttpEnv_getRequestHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(HttpEnv, getRequestBody, ai_HttpEnv_getRequestBody, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + + PHP_ME(HttpEnv, getResponseStatusForCode, ai_HttpEnv_getResponseStatusForCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(HttpEnv, getResponseStatusForAllCodes, ai_HttpEnv_getResponseStatusForAllCodes, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + + PHP_ME(HttpEnv, getResponseHeader, ai_HttpEnv_getResponseHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(HttpEnv, getResponseCode, ai_HttpEnv_getResponseCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(HttpEnv, setResponseHeader, ai_HttpEnv_setResponseHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(HttpEnv, setResponseCode, ai_HttpEnv_setResponseCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + + PHP_ME(HttpEnv, negotiateLanguage, ai_HttpEnv_negotiateLanguage, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(HttpEnv, negotiateContentType, ai_HttpEnv_negotiateContentType, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(HttpEnv, negotiateEncoding, ai_HttpEnv_negotiateEncoding, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(HttpEnv, negotiateCharset, ai_HttpEnv_negotiateCharset, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(HttpEnv, negotiate, ai_HttpEnv_negotiate, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + + EMPTY_FUNCTION_ENTRY +}; + +#ifdef PHP_HTTP_HAVE_JSON +#include "ext/json/php_json.h" + +static SAPI_POST_HANDLER_FUNC(php_http_json_post_handler) +{ + zval *zarg = arg; + char *json_str = NULL; + size_t json_len = 0; + +#if PHP_VERSION_ID >= 50600 + php_http_message_body_to_string(php_http_env_get_request_body(TSRMLS_C), + &json_str, &json_len, 0, -1); +#else + json_str = SG(request_info).raw_post_data; + json_len = SG(request_info).raw_post_data_length; +#endif + + if (json_len) { + zval_dtor(zarg); + ZVAL_NULL(zarg); + php_json_decode(zarg, json_str, json_len, 1, PG(max_input_nesting_level) TSRMLS_CC); + } +#if PHP_VERSION_ID >= 50600 + STR_FREE(json_str); +#endif + + /* always let $_POST be array() */ + if (Z_TYPE_P(zarg) == IS_NULL) { + array_init(zarg); + } +} + +static void php_http_env_register_json_handler(TSRMLS_D) +{ + sapi_post_entry entry = {NULL, 0, NULL, NULL}; + + entry.post_reader = sapi_read_standard_form_data; + entry.post_handler = php_http_json_post_handler; + + entry.content_type = "text/json"; + entry.content_type_len = lenof("text/json"); + sapi_register_post_entry(&entry TSRMLS_CC); + + entry.content_type = "application/json"; + entry.content_type_len = lenof("application/json"); + sapi_register_post_entry(&entry TSRMLS_CC); +} +#endif + +zend_class_entry *php_http_env_class_entry; + +PHP_MINIT_FUNCTION(http_env) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "Env", php_http_env_methods); + php_http_env_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + +#ifdef PHP_HTTP_HAVE_JSON + php_http_env_register_json_handler(TSRMLS_C); +#endif + + return SUCCESS; +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_env.h b/php_http_env.h new file mode 100644 index 0000000..dac10da --- /dev/null +++ b/php_http_env.h @@ -0,0 +1,90 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_ENV_H +#define PHP_HTTP_ENV_H + +#include "php_http_message_body.h" +#include "php_http_version.h" + +struct php_http_env_globals { + zval *server_var; + char *etag_mode; + + struct { + time_t time; + HashTable *headers; + php_http_message_body_t *body; + } request; +}; + +typedef enum php_http_content_encoding { + PHP_HTTP_CONTENT_ENCODING_NONE, + PHP_HTTP_CONTENT_ENCODING_GZIP +} php_http_content_encoding_t; + +typedef enum php_http_range_status { + PHP_HTTP_RANGE_NO, + PHP_HTTP_RANGE_OK, + PHP_HTTP_RANGE_ERR +} php_http_range_status_t; + +PHP_HTTP_API php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t entity_length, php_http_message_t *request TSRMLS_DC); +PHP_HTTP_API void php_http_env_get_request_headers(HashTable *headers TSRMLS_DC); +PHP_HTTP_API char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request TSRMLS_DC); +PHP_HTTP_API int php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request TSRMLS_DC); +PHP_HTTP_API php_http_message_body_t *php_http_env_get_request_body(TSRMLS_D); +PHP_HTTP_API const char *php_http_env_get_request_method(php_http_message_t *request TSRMLS_DC); + +typedef enum php_http_content_disposition { + PHP_HTTP_CONTENT_DISPOSITION_NONE, + PHP_HTTP_CONTENT_DISPOSITION_INLINE, + PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT +} php_http_content_disposition_t; + +typedef enum php_http_cache_status { + PHP_HTTP_CACHE_NO, + PHP_HTTP_CACHE_HIT, + PHP_HTTP_CACHE_MISS +} php_http_cache_status_t; + +PHP_HTTP_API long php_http_env_get_response_code(TSRMLS_D); +PHP_HTTP_API const char *php_http_env_get_response_status_for_code(unsigned code); +PHP_HTTP_API STATUS php_http_env_get_response_headers(HashTable *headers_ht TSRMLS_DC); +PHP_HTTP_API char *php_http_env_get_response_header(const char *name_str, size_t name_len TSRMLS_DC); +PHP_HTTP_API STATUS php_http_env_set_response_code(long http_code TSRMLS_DC); +PHP_HTTP_API STATUS php_http_env_set_response_protocol_version(php_http_version_t *v TSRMLS_DC); +PHP_HTTP_API STATUS php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace TSRMLS_DC); +PHP_HTTP_API STATUS php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace TSRMLS_DC); +PHP_HTTP_API STATUS php_http_env_set_response_header_format(long http_code, zend_bool replace TSRMLS_DC, const char *fmt, ...); +PHP_HTTP_API STATUS php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv TSRMLS_DC); + +PHP_HTTP_API zval *php_http_env_get_server_var(const char *key_str, size_t key_len, zend_bool check TSRMLS_DC); +#define php_http_env_got_server_var(v) (NULL != php_http_env_get_server_var((v), strlen(v), 1 TSRMLS_CC)) +PHP_HTTP_API zval *php_http_env_get_superglobal(const char *key, size_t key_len TSRMLS_DC); + +PHP_HTTP_API zend_class_entry *php_http_env_class_entry; +PHP_MINIT_FUNCTION(http_env); +PHP_RINIT_FUNCTION(http_env); +PHP_RSHUTDOWN_FUNCTION(http_env); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_env_request.c b/php_http_env_request.c new file mode 100644 index 0000000..01c2f6d --- /dev/null +++ b/php_http_env_request.c @@ -0,0 +1,252 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +static int grab_file(void *zpp TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) +{ + zval *zfiles, **name, **zname, **error, **zerror, **type, **ztype, **size, **zsize, **tmp_name = zpp; + zend_hash_key *file_key; + + zfiles = (zval *) va_arg(argv, zval *); + file_key = (zend_hash_key *) va_arg(argv, zend_hash_key *); + name = (zval **) va_arg(argv, zval **); + size = (zval **) va_arg(argv, zval **); + type = (zval **) va_arg(argv, zval **); + error = (zval **) va_arg(argv, zval **); + + if (SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(name), key->h, (void *) &zname) + && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(size), key->h, (void *) &zsize) + && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(type), key->h, (void *) &ztype) + && SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(error), key->h, (void *) &zerror) + ) { + zval *entry, **array; + + MAKE_STD_ZVAL(entry); + array_init(entry); + + Z_ADDREF_PP(tmp_name); + add_assoc_zval_ex(entry, ZEND_STRS("file"), *tmp_name); + Z_ADDREF_PP(zname); + add_assoc_zval_ex(entry, ZEND_STRS("name"), *zname); + Z_ADDREF_PP(zsize); + add_assoc_zval_ex(entry, ZEND_STRS("size"), *zsize); + Z_ADDREF_PP(ztype); + add_assoc_zval_ex(entry, ZEND_STRS("type"), *ztype); + Z_ADDREF_PP(zerror); + add_assoc_zval_ex(entry, ZEND_STRS("error"), *zerror); + + if (SUCCESS == zend_hash_quick_find(Z_ARRVAL_P(zfiles), file_key->arKey, file_key->nKeyLength, file_key->h, (void *) &array)) { + add_next_index_zval(*array, entry); + } else { + zval *tmp; + + MAKE_STD_ZVAL(tmp); + array_init(tmp); + add_next_index_zval(tmp, entry); + zend_hash_quick_update(Z_ARRVAL_P(zfiles), file_key->arKey, file_key->nKeyLength, file_key->h, (void *) &tmp, sizeof(zval *), NULL); + } + } + + return ZEND_HASH_APPLY_KEEP; +} + +static int grab_files(void *zpp TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) +{ + zval *zfiles, **name, **tmp_name, **error, **type, **size, **val = zpp; + + zfiles = (zval *) va_arg(argv, zval *); + + if (Z_TYPE_PP(val) == IS_ARRAY + && SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("tmp_name"), (void *) &tmp_name) + && SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("name"), (void *) &name) + && SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("size"), (void *) &size) + && SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("type"), (void *) &type) + && SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("error"), (void *) &error) + ) { + int count; + + if (Z_TYPE_PP(tmp_name) == IS_ARRAY && (count = zend_hash_num_elements(Z_ARRVAL_PP(tmp_name))) > 1) { + if (count == zend_hash_num_elements(Z_ARRVAL_PP(name)) + && count == zend_hash_num_elements(Z_ARRVAL_PP(size)) + && count == zend_hash_num_elements(Z_ARRVAL_PP(type)) + && count == zend_hash_num_elements(Z_ARRVAL_PP(error)) + ) { + zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp_name) TSRMLS_CC, grab_file, 6, zfiles, key, name, size, type, error); + } else { + /* wat?! */ + return ZEND_HASH_APPLY_STOP; + } + } else { + zval *cpy, **tmp; + + MAKE_STD_ZVAL(cpy); + MAKE_COPY_ZVAL(val, cpy); + if (SUCCESS == zend_hash_find(Z_ARRVAL_P(cpy), ZEND_STRS("tmp_name"), (void *) &tmp)) { + Z_ADDREF_PP(tmp); + add_assoc_zval_ex(cpy, ZEND_STRS("file"), *tmp); + zend_hash_del_key_or_index(Z_ARRVAL_P(cpy), ZEND_STRS("tmp_name"), 0, HASH_DEL_KEY); + } + zend_hash_quick_update(Z_ARRVAL_P(zfiles), key->arKey, key->nKeyLength, key->h, (void *) &cpy, sizeof(zval *), NULL); + } + } + + return ZEND_HASH_APPLY_KEEP; +} + +#define PHP_HTTP_ENV_REQUEST_OBJECT_INIT(obj) \ + do { \ + if (!obj->message) { \ + obj->message = php_http_message_init_env(NULL, PHP_HTTP_REQUEST TSRMLS_CC); \ + } \ + } while(0) + + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest___construct, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvRequest, __construct) +{ + php_http_message_object_t *obj; + zval *zsg, *zqs; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + obj->body = NULL; + + php_http_expect(obj->message = php_http_message_init_env(obj->message, PHP_HTTP_REQUEST TSRMLS_CC), unexpected_val, return); + + zsg = php_http_env_get_superglobal(ZEND_STRL("_GET") TSRMLS_CC); + MAKE_STD_ZVAL(zqs); + object_init_ex(zqs, php_http_querystring_class_entry); + php_http_expect(SUCCESS == php_http_querystring_ctor(zqs, zsg TSRMLS_CC), unexpected_val, + zval_ptr_dtor(&zqs); + return; + ); + zend_update_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("query"), zqs TSRMLS_CC); + zval_ptr_dtor(&zqs); + + zsg = php_http_env_get_superglobal(ZEND_STRL("_POST") TSRMLS_CC); + MAKE_STD_ZVAL(zqs); + object_init_ex(zqs, php_http_querystring_class_entry); + php_http_expect(SUCCESS == php_http_querystring_ctor(zqs, zsg TSRMLS_CC), unexpected_val, + zval_ptr_dtor(&zqs); + return; + ); + zend_update_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("form"), zqs TSRMLS_CC); + zval_ptr_dtor(&zqs); + + MAKE_STD_ZVAL(zqs); + array_init(zqs); + if ((zsg = php_http_env_get_superglobal(ZEND_STRL("_FILES") TSRMLS_CC))) { + zend_hash_apply_with_arguments(Z_ARRVAL_P(zsg) TSRMLS_CC, grab_files, 1, zqs); + } + zend_update_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("files"), zqs TSRMLS_CC); + zval_ptr_dtor(&zqs); +} + +#define call_querystring_get(prop) \ + do {\ + zend_fcall_info fci; \ + zend_fcall_info_cache fcc; \ + zval *rv, mn, ***args = ecalloc(sizeof(zval **), ZEND_NUM_ARGS()); \ + zval *qs = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(prop), 0 TSRMLS_CC); \ + \ + INIT_PZVAL(&mn); \ + array_init(&mn); \ + Z_ADDREF_P(qs); \ + add_next_index_zval(&mn, qs); \ + add_next_index_stringl(&mn, ZEND_STRL("get"), 1); \ + zend_fcall_info_init(&mn, 0, &fci, &fcc, NULL, NULL TSRMLS_CC); \ + zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args); \ + zend_fcall_info_argp(&fci TSRMLS_CC, ZEND_NUM_ARGS(), args); \ + zend_fcall_info_call(&fci, &fcc, &rv, NULL TSRMLS_CC); \ + zend_fcall_info_args_clear(&fci, 1); \ + efree(args); \ + zval_dtor(&mn); \ + RETVAL_ZVAL(rv, 0, 1); \ + } while(0); + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getForm, 0, 0, 0) + ZEND_ARG_INFO(0, name) + ZEND_ARG_INFO(0, type) + ZEND_ARG_INFO(0, defval) + ZEND_ARG_INFO(0, delete) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvRequest, getForm) +{ + if (ZEND_NUM_ARGS()) { + call_querystring_get("form"); + } else { + zval *zform = zend_read_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("form"), 0 TSRMLS_CC); + RETURN_ZVAL(zform, 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getQuery, 0, 0, 0) + ZEND_ARG_INFO(0, name) + ZEND_ARG_INFO(0, type) + ZEND_ARG_INFO(0, defval) + ZEND_ARG_INFO(0, delete) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvRequest, getQuery) +{ + if (ZEND_NUM_ARGS()) { + call_querystring_get("query"); + } else { + zval *zquery = zend_read_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("query"), 0 TSRMLS_CC); + RETURN_ZVAL(zquery, 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getFiles, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvRequest, getFiles) +{ + if (SUCCESS == zend_parse_parameters_none()) { + zval *zfiles = zend_read_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("files"), 0 TSRMLS_CC); + RETURN_ZVAL(zfiles, 1, 0); + } +} + +static zend_function_entry php_http_env_request_methods[] = { + PHP_ME(HttpEnvRequest, __construct, ai_HttpEnvRequest___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpEnvRequest, getForm, ai_HttpEnvRequest_getForm, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvRequest, getQuery, ai_HttpEnvRequest_getQuery, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvRequest, getFiles, ai_HttpEnvRequest_getFiles, ZEND_ACC_PUBLIC) + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_env_request_class_entry; + +PHP_MINIT_FUNCTION(http_env_request) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Request", php_http_env_request_methods); + php_http_env_request_class_entry = zend_register_internal_class_ex(&ce, php_http_message_class_entry, NULL TSRMLS_CC); + + zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("query"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("form"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("files"), ZEND_ACC_PROTECTED TSRMLS_CC); + + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_util_object.h b/php_http_env_request.h similarity index 71% rename from php_http_util_object.h rename to php_http_env_request.h index 2cb7279..f6b8f40 100644 --- a/php_http_util_object.h +++ b/php_http_env_request.h @@ -6,22 +6,16 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | + | Copyright (c) 2004-2013, Michael Wallner | +--------------------------------------------------------------------+ */ -/* $Id$ */ +#ifndef PHP_HTTP_ENV_REQUEST_H +#define PHP_HTTP_ENV_REQUEST_H -#ifndef PHP_HTTP_UTIL_OBJECT_H -#define PHP_HTTP_UTIL_OBJECT_H -#ifdef ZEND_ENGINE_2 - -extern zend_class_entry *http_util_object_ce; -extern zend_function_entry http_util_object_fe[]; - -extern PHP_MINIT_FUNCTION(http_util_object); +PHP_HTTP_API zend_class_entry *php_http_env_request_class_entry; +PHP_MINIT_FUNCTION(http_env_request); -#endif #endif /* @@ -32,4 +26,3 @@ extern PHP_MINIT_FUNCTION(http_util_object); * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ - diff --git a/php_http_env_response.c b/php_http_env_response.c new file mode 100644 index 0000000..cb52752 --- /dev/null +++ b/php_http_env_response.c @@ -0,0 +1,1339 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +static void set_option(zval *options, const char *name_str, size_t name_len, int type, void *value_ptr, size_t value_len TSRMLS_DC) +{ + if (Z_TYPE_P(options) == IS_OBJECT) { + if (value_ptr) { + switch (type) { + case IS_DOUBLE: + zend_update_property_double(Z_OBJCE_P(options), options, name_str, name_len, *(double *)value_ptr TSRMLS_CC); + break; + case IS_LONG: + zend_update_property_long(Z_OBJCE_P(options), options, name_str, name_len, *(long *)value_ptr TSRMLS_CC); + break; + case IS_STRING: + zend_update_property_stringl(Z_OBJCE_P(options), options, name_str, name_len, value_ptr, value_len TSRMLS_CC); + break; + case IS_OBJECT: + zend_update_property(Z_OBJCE_P(options), options, name_str, name_len, value_ptr TSRMLS_CC); + break; + } + } else { + zend_update_property_null(Z_OBJCE_P(options), options, name_str, name_len TSRMLS_CC); + } + } else { + convert_to_array(options); + if (value_ptr) { + switch (type) { + case IS_DOUBLE: + add_assoc_double_ex(options, name_str, name_len + 1, *(double *)value_ptr); + break; + case IS_LONG: + add_assoc_long_ex(options, name_str, name_len + 1, *(long *)value_ptr); + break; + case IS_STRING: { + char *value = estrndup(value_ptr, value_len); + add_assoc_stringl_ex(options, name_str, name_len + 1, value, value_len, 0); + break; + case IS_OBJECT: + Z_ADDREF_P(value_ptr); + add_assoc_zval_ex(options, name_str, name_len + 1, value_ptr); + break; + } + } + } else { + add_assoc_null_ex(options, name_str, name_len + 1); + } + } +} +static zval *get_option(zval *options, const char *name_str, size_t name_len TSRMLS_DC) +{ + zval *val, **valptr; + + if (Z_TYPE_P(options) == IS_OBJECT) { + val = zend_read_property(Z_OBJCE_P(options), options, name_str, name_len, 0 TSRMLS_CC); + } else { + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(options), name_str, name_len + 1, (void *) &valptr)) { + val = *valptr; + } else { + val = NULL; + } + } + if (val) { + Z_ADDREF_P(val); + } + return val; +} +static php_http_message_body_t *get_body(zval *options TSRMLS_DC) +{ + zval *zbody; + php_http_message_body_t *body = NULL; + + if ((zbody = get_option(options, ZEND_STRL("body") TSRMLS_CC))) { + if ((Z_TYPE_P(zbody) == IS_OBJECT) && instanceof_function(Z_OBJCE_P(zbody), php_http_message_body_class_entry TSRMLS_CC)) { + php_http_message_body_object_t *body_obj = zend_object_store_get_object(zbody TSRMLS_CC); + + body = body_obj->body; + } + zval_ptr_dtor(&zbody); + } + + return body; +} +static php_http_message_t *get_request(zval *options TSRMLS_DC) +{ + zval *zrequest; + php_http_message_t *request = NULL; + + if ((zrequest = get_option(options, ZEND_STRL("request") TSRMLS_CC))) { + if (Z_TYPE_P(zrequest) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zrequest), php_http_message_class_entry TSRMLS_CC)) { + php_http_message_object_t *request_obj = zend_object_store_get_object(zrequest TSRMLS_CC); + + request = request_obj->message; + } + zval_ptr_dtor(&zrequest); + } + + return request; +} + +php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *options, const char *header_str, size_t header_len, php_http_message_t *request TSRMLS_DC) +{ + php_http_cache_status_t ret = PHP_HTTP_CACHE_NO; + int free_etag = 0; + char *header = NULL, *etag; + php_http_message_body_t *body; + zval *zetag; + + + if (!(body = get_body(options TSRMLS_CC))) { + return ret; + } + + if ((zetag = get_option(options, ZEND_STRL("etag") TSRMLS_CC))) { + zval *zetag_copy = php_http_ztyp(IS_STRING, zetag); + zval_ptr_dtor(&zetag); + zetag = zetag_copy; + } + + if (zetag && Z_STRLEN_P(zetag)) { + etag = Z_STRVAL_P(zetag); + } else if ((etag = php_http_message_body_etag(body))) { + set_option(options, ZEND_STRL("etag"), IS_STRING, etag, strlen(etag) TSRMLS_CC); + free_etag = 1; + } + + if (zetag) { + zval_ptr_dtor(&zetag); + } + + if (etag && (header = php_http_env_get_request_header(header_str, header_len, NULL, request TSRMLS_CC))) { + ret = php_http_match(header, etag, PHP_HTTP_MATCH_WORD) ? PHP_HTTP_CACHE_HIT : PHP_HTTP_CACHE_MISS; + } + + if (free_etag) { + efree(etag); + } + + STR_FREE(header); + return ret; +} + +php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *options, const char *header_str, size_t header_len, php_http_message_t *request TSRMLS_DC) +{ + php_http_cache_status_t ret = PHP_HTTP_CACHE_NO; + char *header; + time_t ums, lm = 0; + php_http_message_body_t *body; + zval *zlm; + + if (!(body = get_body(options TSRMLS_CC))) { + return ret; + } + + if ((zlm = get_option(options, ZEND_STRL("lastModified") TSRMLS_CC))) { + zval *zlm_copy = php_http_ztyp(IS_LONG, zlm); + zval_ptr_dtor(&zlm); + zlm = zlm_copy; + } + + if (zlm && Z_LVAL_P(zlm) > 0) { + lm = Z_LVAL_P(zlm); + } else { + lm = php_http_message_body_mtime(body); + set_option(options, ZEND_STRL("lastModified"), IS_LONG, &lm, 0 TSRMLS_CC); + } + + if (zlm) { + zval_ptr_dtor(&zlm); + } + + if ((header = php_http_env_get_request_header(header_str, header_len, NULL, request TSRMLS_CC))) { + ums = php_parse_date(header, NULL); + + if (ums > 0 && ums >= lm) { + ret = PHP_HTTP_CACHE_HIT; + } else { + ret = PHP_HTTP_CACHE_MISS; + } + } + + STR_FREE(header); + return ret; +} + +static zend_bool php_http_env_response_is_cacheable(php_http_env_response_t *r, php_http_message_t *request) +{ + TSRMLS_FETCH_FROM_CTX(r->ts); + + if (r->ops->get_status(r) >= 400) { + return 0; + } + + if (php_http_env_got_request_header(ZEND_STRL("Authorization"), request TSRMLS_CC)) { + return 0; + } + + if (-1 == php_http_select_str(php_http_env_get_request_method(request TSRMLS_CC), 2, "HEAD", "GET")) { + return 0; + } + + return 1; +} + +static size_t output(void *context, char *buf, size_t len TSRMLS_DC) +{ + php_http_env_response_t *r = context; + + r->ops->write(r, buf, len); + + /* we really only need to flush when throttling is enabled, + because we push the data as fast as possible anyway if not */ + if (r->throttle.delay >= PHP_HTTP_DIFFSEC) { + r->ops->flush(r); + php_http_sleep(r->throttle.delay); + } + return len; +} + +#define php_http_env_response_send_done(r) php_http_env_response_send_data((r), NULL, 0) +static STATUS php_http_env_response_send_data(php_http_env_response_t *r, const char *buf, size_t len) +{ + size_t chunk = r->throttle.chunk ? r->throttle.chunk : PHP_HTTP_SENDBUF_SIZE; + TSRMLS_FETCH_FROM_CTX(r->ts); + + if (r->content.encoder) { + char *enc_str = NULL; + size_t enc_len = 0; + + if (buf) { + if (SUCCESS != php_http_encoding_stream_update(r->content.encoder, buf, len, &enc_str, &enc_len)) { + return FAILURE; + } + } else { + if (SUCCESS != php_http_encoding_stream_finish(r->content.encoder, &enc_str, &enc_len)) { + return FAILURE; + } + } + + if (enc_str) { + php_http_buffer_chunked_output(&r->buffer, enc_str, enc_len, buf ? chunk : 0, output, r TSRMLS_CC); + STR_FREE(enc_str); + } + } else { + php_http_buffer_chunked_output(&r->buffer, buf, len, buf ? chunk : 0, output, r TSRMLS_CC); + } + + return SUCCESS; +} + +php_http_env_response_t *php_http_env_response_init(php_http_env_response_t *r, zval *options, php_http_env_response_ops_t *ops, void *init_arg TSRMLS_DC) +{ + zend_bool free_r; + + if ((free_r = !r)) { + r = emalloc(sizeof(*r)); + } + memset(r, 0, sizeof(*r)); + + if (ops) { + r->ops = ops; + } else { + r->ops = php_http_env_response_get_sapi_ops(); + } + + r->buffer = php_http_buffer_init(NULL); + + Z_ADDREF_P(options); + r->options = options; + + TSRMLS_SET_CTX(r->ts); + + if (r->ops->init && (SUCCESS != r->ops->init(r, init_arg))) { + if (free_r) { + php_http_env_response_free(&r); + } else { + php_http_env_response_dtor(r); + r = NULL; + } + } + + return r; +} + +void php_http_env_response_dtor(php_http_env_response_t *r) +{ + if (r->ops->dtor) { + r->ops->dtor(r); + } + php_http_buffer_free(&r->buffer); + zval_ptr_dtor(&r->options); + STR_FREE(r->content.type); + STR_FREE(r->content.encoding); + if (r->content.encoder) { + php_http_encoding_stream_free(&r->content.encoder); + } +} + +void php_http_env_response_free(php_http_env_response_t **r) +{ + if (*r) { + php_http_env_response_dtor(*r); + efree(*r); + *r = NULL; + } +} + +static STATUS php_http_env_response_send_head(php_http_env_response_t *r, php_http_message_t *request) +{ + STATUS ret = SUCCESS; + zval *zoption, *options = r->options; + TSRMLS_FETCH_FROM_CTX(r->ts); + + if (r->done) { + return ret; + } + + if ((zoption = get_option(options, ZEND_STRL("responseCode") TSRMLS_CC))) { + zval *zoption_copy = php_http_ztyp(IS_LONG, zoption); + + zval_ptr_dtor(&zoption); + if (Z_LVAL_P(zoption_copy) > 0) { + ret = r->ops->set_status(r, Z_LVAL_P(zoption_copy)); + } + zval_ptr_dtor(&zoption_copy); + } + + if (ret != SUCCESS) { + return ret; + } + + if ((zoption = get_option(options, ZEND_STRL("httpVersion") TSRMLS_CC))) { + php_http_version_t v; + zval *zoption_copy = php_http_ztyp(IS_STRING, zoption); + + zval_ptr_dtor(&zoption); + if (Z_STRLEN_P(zoption_copy) && php_http_version_parse(&v, Z_STRVAL_P(zoption_copy) TSRMLS_CC)) { + ret = r->ops->set_protocol_version(r, &v); + php_http_version_dtor(&v); + } + zval_ptr_dtor(&zoption_copy); + } + + if (ret != SUCCESS) { + return ret; + } + + if ((zoption = get_option(options, ZEND_STRL("headers") TSRMLS_CC))) { + if (Z_TYPE_P(zoption) == IS_ARRAY) { + php_http_header_to_callback(Z_ARRVAL_P(zoption), 0, (php_http_pass_format_callback_t) r->ops->set_header, r TSRMLS_CC); + } + zval_ptr_dtor(&zoption); + } + + if (ret != SUCCESS) { + return ret; + } + + if ((zoption = get_option(options, ZEND_STRL("contentType") TSRMLS_CC))) { + zval *zoption_copy = php_http_ztyp(IS_STRING, zoption); + + zval_ptr_dtor(&zoption); + if (Z_STRLEN_P(zoption_copy) && strchr(Z_STRVAL_P(zoption_copy), '/')) { + if (SUCCESS == (ret = r->ops->set_header(r, "Content-Type: %.*s", Z_STRLEN_P(zoption_copy), Z_STRVAL_P(zoption_copy)))) { + r->content.type = estrndup(Z_STRVAL_P(zoption_copy), Z_STRLEN_P(zoption_copy)); + } + } + zval_ptr_dtor(&zoption_copy); + } + + if (ret != SUCCESS) { + return ret; + } + + if (r->range.status == PHP_HTTP_RANGE_OK) { + if (zend_hash_num_elements(&r->range.values) == 1) { + zval **range, **begin, **end; + + if ( 1 == php_http_array_list(&r->range.values TSRMLS_CC, 1, &range) + && 2 == php_http_array_list(Z_ARRVAL_PP(range) TSRMLS_CC, 2, &begin, &end) + ) { + if (SUCCESS == (ret = r->ops->set_status(r, 206))) { + ret = r->ops->set_header(r, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_PP(begin), Z_LVAL_PP(end), r->content.length); + } + } else { + /* this should never happen */ + zend_hash_destroy(&r->range.values); + ret = FAILURE; + } + } else { + php_http_boundary(r->range.boundary, sizeof(r->range.boundary) TSRMLS_CC); + if (SUCCESS == (ret = r->ops->set_status(r, 206))) { + ret = r->ops->set_header(r, "Content-Type: multipart/byteranges; boundary=%s", r->range.boundary); + } + } + } else { + if ((zoption = get_option(options, ZEND_STRL("cacheControl") TSRMLS_CC))) { + zval *zoption_copy = php_http_ztyp(IS_STRING, zoption); + + zval_ptr_dtor(&zoption); + if (Z_STRLEN_P(zoption_copy)) { + ret = r->ops->set_header(r, "Cache-Control: %.*s", Z_STRLEN_P(zoption_copy), Z_STRVAL_P(zoption_copy)); + } + zval_ptr_dtor(&zoption_copy); + } + + if (ret != SUCCESS) { + return ret; + } + + if ((zoption = get_option(options, ZEND_STRL("contentDisposition") TSRMLS_CC))) { + zval *zoption_copy = php_http_ztyp(IS_ARRAY, zoption); + php_http_buffer_t buf; + + php_http_buffer_init(&buf); + if (php_http_params_to_string(&buf, Z_ARRVAL_P(zoption_copy), ZEND_STRL(","), ZEND_STRL(";"), ZEND_STRL("="), PHP_HTTP_PARAMS_DEFAULT TSRMLS_CC)) { + if (buf.used) { + ret = r->ops->set_header(r, "Content-Disposition: %.*s", buf.used, buf.data); + } + } + + php_http_buffer_dtor(&buf); + zval_ptr_dtor(&zoption_copy); + zval_ptr_dtor(&zoption); + } + + if (ret != SUCCESS) { + return ret; + } + + if ((zoption = get_option(options, ZEND_STRL("contentEncoding") TSRMLS_CC))) { + zval *zoption_copy = php_http_ztyp(IS_LONG, zoption); + zval zsupported; + HashTable *result = NULL; + + zval_ptr_dtor(&zoption); + switch (Z_LVAL_P(zoption_copy)) { + case PHP_HTTP_CONTENT_ENCODING_GZIP: + INIT_PZVAL(&zsupported); + array_init(&zsupported); + add_next_index_stringl(&zsupported, ZEND_STRL("none"), 1); + add_next_index_stringl(&zsupported, ZEND_STRL("gzip"), 1); + add_next_index_stringl(&zsupported, ZEND_STRL("deflate"), 1); + + if ((result = php_http_negotiate_encoding(Z_ARRVAL(zsupported), request TSRMLS_CC))) { + char *key_str = NULL; + uint key_len = 0; + + zend_hash_internal_pointer_reset(result); + if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key_str, &key_len, NULL, 0, NULL)) { + if (!strcmp(key_str, "gzip")) { + if (!(r->content.encoder = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_GZIP TSRMLS_CC))) { + ret = FAILURE; + } else if (SUCCESS == (ret = r->ops->set_header(r, "Content-Encoding: gzip"))) { + r->content.encoding = estrndup(key_str, key_len - 1); + } + } else if (!strcmp(key_str, "deflate")) { + if (!(r->content.encoder = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_ZLIB TSRMLS_CC))) { + ret = FAILURE; + } else if (SUCCESS == (ret = r->ops->set_header(r, "Content-Encoding: deflate"))) { + r->content.encoding = estrndup(key_str, key_len - 1); + } + } else { + ret = r->ops->del_header(r, ZEND_STRL("Content-Encoding")); + } + + if (SUCCESS == ret) { + ret = r->ops->add_header(r, "Vary: Accept-Encoding"); + } + } + + zend_hash_destroy(result); + FREE_HASHTABLE(result); + } + + zval_dtor(&zsupported); + break; + + case PHP_HTTP_CONTENT_ENCODING_NONE: + default: + ret = r->ops->del_header(r, ZEND_STRL("Content-Encoding")); + break; + } + zval_ptr_dtor(&zoption_copy); + } + + if (SUCCESS != ret) { + return ret; + } + + if (php_http_env_response_is_cacheable(r, request)) { + switch (php_http_env_is_response_cached_by_etag(options, ZEND_STRL("If-None-Match"), request TSRMLS_CC)) { + case PHP_HTTP_CACHE_MISS: + break; + + case PHP_HTTP_CACHE_NO: + if (PHP_HTTP_CACHE_HIT != php_http_env_is_response_cached_by_last_modified(options, ZEND_STRL("If-Modified-Since"), request TSRMLS_CC)) { + break; + } + /* no break */ + + case PHP_HTTP_CACHE_HIT: + ret = r->ops->set_status(r, 304); + r->done = 1; + break; + } + + if ((zoption = get_option(options, ZEND_STRL("etag") TSRMLS_CC))) { + zval *zoption_copy = php_http_ztyp(IS_STRING, zoption); + + zval_ptr_dtor(&zoption); + if (*Z_STRVAL_P(zoption_copy) != '"' && strncmp(Z_STRVAL_P(zoption_copy), "W/\"", 3)) { + ret = r->ops->set_header(r, "ETag: \"%s\"", Z_STRVAL_P(zoption_copy)); + } else { + ret = r->ops->set_header(r, "ETag: %s", Z_STRVAL_P(zoption_copy)); + } + zval_ptr_dtor(&zoption_copy); + } + if ((zoption = get_option(options, ZEND_STRL("lastModified") TSRMLS_CC))) { + zval *zoption_copy = php_http_ztyp(IS_LONG, zoption); + + zval_ptr_dtor(&zoption); + if (Z_LVAL_P(zoption_copy)) { + char *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), Z_LVAL_P(zoption_copy), 0 TSRMLS_CC); + if (date) { + ret = r->ops->set_header(r, "Last-Modified: %s", date); + efree(date); + } + } + zval_ptr_dtor(&zoption_copy); + } + } + } + + return ret; +} + +static STATUS php_http_env_response_send_body(php_http_env_response_t *r) +{ + STATUS ret = SUCCESS; + zval *zoption; + php_http_message_body_t *body; + TSRMLS_FETCH_FROM_CTX(r->ts); + + if (r->done) { + return ret; + } + + if ((body = get_body(r->options TSRMLS_CC))) { + if ((zoption = get_option(r->options, ZEND_STRL("throttleDelay") TSRMLS_CC))) { + if (Z_TYPE_P(zoption) == IS_DOUBLE) { + r->throttle.delay = Z_DVAL_P(zoption); + } + zval_ptr_dtor(&zoption); + } + if ((zoption = get_option(r->options, ZEND_STRL("throttleChunk") TSRMLS_CC))) { + if (Z_TYPE_P(zoption) == IS_LONG) { + r->throttle.chunk = Z_LVAL_P(zoption); + } + zval_ptr_dtor(&zoption); + } + + if (r->range.status == PHP_HTTP_RANGE_OK) { + if (zend_hash_num_elements(&r->range.values) == 1) { + /* single range */ + zval **range, **begin, **end; + + if ( 1 == php_http_array_list(&r->range.values TSRMLS_CC, 1, &range) + && 2 == php_http_array_list(Z_ARRVAL_PP(range) TSRMLS_CC, 2, &begin, &end) + ) { + /* send chunk */ + ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, Z_LVAL_PP(begin), Z_LVAL_PP(end) - Z_LVAL_PP(begin) + 1); + if (ret == SUCCESS) { + ret = php_http_env_response_send_done(r); + } + zend_hash_destroy(&r->range.values); + } else { + /* this should never happen */ + zend_hash_destroy(&r->range.values); + r->ops->set_status(r, 500); + ret = FAILURE; + } + + } else { + /* send multipart/byte-ranges message */ + HashPosition pos; + zval **chunk; + + FOREACH_HASH_VAL(pos, &r->range.values, chunk) { + zval **begin, **end; + + if (2 == php_http_array_list(Z_ARRVAL_PP(chunk) TSRMLS_CC, 2, &begin, &end)) { + php_http_buffer_appendf(r->buffer, + PHP_HTTP_CRLF + "--%s" PHP_HTTP_CRLF + "Content-Type: %s" PHP_HTTP_CRLF + "Content-Range: bytes %ld-%ld/%zu" PHP_HTTP_CRLF PHP_HTTP_CRLF, + /* - */ + r->range.boundary, + r->content.type ? r->content.type : "application/octet-stream", + Z_LVAL_PP(begin), + Z_LVAL_PP(end), + r->content.length + ); + ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, Z_LVAL_PP(begin), Z_LVAL_PP(end) - Z_LVAL_PP(begin) + 1); + } + } + + if (ret == SUCCESS) { + php_http_buffer_appendf(r->buffer, PHP_HTTP_CRLF "--%s--", r->range.boundary); + ret = php_http_env_response_send_done(r); + } + zend_hash_destroy(&r->range.values); + } + + } else { + ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, 0, 0); + if (ret == SUCCESS) { + ret = php_http_env_response_send_done(r); + } + } + } + return ret; +} + +STATUS php_http_env_response_send(php_http_env_response_t *r) +{ + php_http_message_t *request; + php_http_message_body_t *body; + TSRMLS_FETCH_FROM_CTX(r->ts); + + request = get_request(r->options TSRMLS_CC); + + /* check for ranges */ + if ((body = get_body(r->options TSRMLS_CC))) { + r->content.length = php_http_message_body_size(body); + + if (SUCCESS != r->ops->set_header(r, "Accept-Ranges: bytes")) { + return FAILURE; + } else { + zend_hash_init(&r->range.values, 0, NULL, ZVAL_PTR_DTOR, 0); + r->range.status = php_http_env_get_request_ranges(&r->range.values, r->content.length, request TSRMLS_CC); + + switch (r->range.status) { + case PHP_HTTP_RANGE_NO: + zend_hash_destroy(&r->range.values); + break; + + case PHP_HTTP_RANGE_ERR: + if (php_http_env_got_request_header(ZEND_STRL("If-Range"), request TSRMLS_CC)) { + r->range.status = PHP_HTTP_RANGE_NO; + zend_hash_destroy(&r->range.values); + } else { + r->done = 1; + zend_hash_destroy(&r->range.values); + if (SUCCESS != r->ops->set_status(r, 416)) { + return FAILURE; + } + if (SUCCESS != r->ops->set_header(r, "Content-Range: bytes */%zu", r->content.length)) { + return FAILURE; + } + } + break; + + case PHP_HTTP_RANGE_OK: + if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(r->options, ZEND_STRL("If-Range"), request TSRMLS_CC) + || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(r->options, ZEND_STRL("If-Range"), request TSRMLS_CC) + ) { + r->range.status = PHP_HTTP_RANGE_NO; + zend_hash_destroy(&r->range.values); + break; + } + if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(r->options, ZEND_STRL("If-Match"), request TSRMLS_CC) + || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(r->options, ZEND_STRL("If-Unmodified-Since"), request TSRMLS_CC) + || PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(r->options, ZEND_STRL("Unless-Modified-Since"), request TSRMLS_CC) + ) { + r->done = 1; + zend_hash_destroy(&r->range.values); + if (SUCCESS != r->ops->set_status(r, 412)) { + return FAILURE; + } + break; + } + + break; + } + } + } + + if (SUCCESS != php_http_env_response_send_head(r, request)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to send response headers"); + return FAILURE; + } + + if (SUCCESS != php_http_env_response_send_body(r)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to send response body"); + return FAILURE; + } + + if (SUCCESS != r->ops->finish(r)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to finish response"); + return FAILURE; + } + + return SUCCESS; +} + +static long php_http_env_response_sapi_get_status(php_http_env_response_t *r) +{ + TSRMLS_FETCH_FROM_CTX(r->ts); + + return php_http_env_get_response_code(TSRMLS_C); +} +static STATUS php_http_env_response_sapi_set_status(php_http_env_response_t *r, long http_code) +{ + TSRMLS_FETCH_FROM_CTX(r->ts); + + return php_http_env_set_response_code(http_code TSRMLS_CC); +} +static STATUS php_http_env_response_sapi_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v) +{ + TSRMLS_FETCH_FROM_CTX(r->ts); + + return php_http_env_set_response_protocol_version(v TSRMLS_CC); +} +static STATUS php_http_env_response_sapi_set_header(php_http_env_response_t *r, const char *fmt, ...) +{ + STATUS ret; + va_list args; + TSRMLS_FETCH_FROM_CTX(r->ts); + + va_start(args, fmt); + ret = php_http_env_set_response_header_va(0, 1, fmt, args TSRMLS_CC); + va_end(args); + + return ret; +} +static STATUS php_http_env_response_sapi_add_header(php_http_env_response_t *r, const char *fmt, ...) +{ + STATUS ret; + va_list args; + TSRMLS_FETCH_FROM_CTX(r->ts); + + va_start(args, fmt); + ret = php_http_env_set_response_header_va(0, 0, fmt, args TSRMLS_CC); + va_end(args); + + return ret; +} +static STATUS php_http_env_response_sapi_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len) +{ + TSRMLS_FETCH_FROM_CTX(r->ts); + + return php_http_env_set_response_header_value(0, header_str, header_len, NULL, 1 TSRMLS_CC); +} +static STATUS php_http_env_response_sapi_write(php_http_env_response_t *r, const char *data_str, size_t data_len) +{ + TSRMLS_FETCH_FROM_CTX(r->ts); + + if (0 < PHPWRITE(data_str, data_len)) { + return SUCCESS; + } + return FAILURE; +} +static STATUS php_http_env_response_sapi_flush(php_http_env_response_t *r) +{ + TSRMLS_FETCH_FROM_CTX(r->ts); + +#if PHP_VERSION_ID >= 50400 + if (php_output_get_level(TSRMLS_C)) { + php_output_flush_all(TSRMLS_C); + } + if (!(php_output_get_status(TSRMLS_C) & PHP_OUTPUT_IMPLICITFLUSH)) { + sapi_flush(TSRMLS_C); + } +#else + php_end_ob_buffer(1, 1 TSRMLS_CC); + sapi_flush(TSRMLS_C); +#endif + + return SUCCESS; +} +static STATUS php_http_env_response_sapi_finish(php_http_env_response_t *r) +{ + return SUCCESS; +} + +static php_http_env_response_ops_t php_http_env_response_sapi_ops = { + NULL, + NULL, + php_http_env_response_sapi_get_status, + php_http_env_response_sapi_set_status, + php_http_env_response_sapi_set_protocol_version, + php_http_env_response_sapi_set_header, + php_http_env_response_sapi_add_header, + php_http_env_response_sapi_del_header, + php_http_env_response_sapi_write, + php_http_env_response_sapi_flush, + php_http_env_response_sapi_finish +}; + +php_http_env_response_ops_t *php_http_env_response_get_sapi_ops(void) +{ + return &php_http_env_response_sapi_ops; +} + +typedef struct php_http_env_response_stream_ctx { + HashTable header; + php_http_version_t version; + long status_code; + + php_stream *stream; + + unsigned started:1; + unsigned finished:1; +} php_http_env_response_stream_ctx_t; + +static STATUS php_http_env_response_stream_init(php_http_env_response_t *r, void *init_arg) +{ + php_http_env_response_stream_ctx_t *ctx; + TSRMLS_FETCH_FROM_CTX(r->ts); + + ctx = ecalloc(1, sizeof(*ctx)); + + ctx->stream = init_arg; + if (SUCCESS != zend_list_addref(ctx->stream->rsrc_id)) { + efree(ctx); + return FAILURE; + } + zend_hash_init(&ctx->header, 0, NULL, ZVAL_PTR_DTOR, 0); + php_http_version_init(&ctx->version, 1, 1 TSRMLS_CC); + ctx->status_code = 200; + + r->ctx = ctx; + + return SUCCESS; +} +static void php_http_env_response_stream_dtor(php_http_env_response_t *r) +{ + php_http_env_response_stream_ctx_t *ctx = r->ctx; + TSRMLS_FETCH_FROM_CTX(r->ts); + + zend_hash_destroy(&ctx->header); + zend_list_delete(ctx->stream->rsrc_id); + efree(ctx); + r->ctx = NULL; +} +static void php_http_env_response_stream_header(php_http_env_response_stream_ctx_t *ctx, HashTable *header TSRMLS_DC) +{ + HashPosition pos; + zval **val; + + FOREACH_HASH_VAL(pos, &ctx->header, val) { + if (Z_TYPE_PP(val) == IS_ARRAY) { + php_http_env_response_stream_header(ctx, Z_ARRVAL_PP(val) TSRMLS_CC); + } else { + php_stream_write(ctx->stream, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); + php_stream_write_string(ctx->stream, PHP_HTTP_CRLF); + } + } +} +static STATUS php_http_env_response_stream_start(php_http_env_response_stream_ctx_t *ctx TSRMLS_DC) +{ + if (ctx->started || ctx->finished) { + return FAILURE; + } + + php_stream_printf(ctx->stream TSRMLS_CC, "HTTP/%u.%u %ld %s" PHP_HTTP_CRLF, ctx->version.major, ctx->version.minor, ctx->status_code, php_http_env_get_response_status_for_code(ctx->status_code)); + php_http_env_response_stream_header(ctx, &ctx->header TSRMLS_CC); + php_stream_write_string(ctx->stream, PHP_HTTP_CRLF); + ctx->started = 1; + return SUCCESS; +} +static long php_http_env_response_stream_get_status(php_http_env_response_t *r) +{ + php_http_env_response_stream_ctx_t *ctx = r->ctx; + + return ctx->status_code; +} +static STATUS php_http_env_response_stream_set_status(php_http_env_response_t *r, long http_code) +{ + php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; + + if (stream_ctx->started || stream_ctx->finished) { + return FAILURE; + } + + stream_ctx->status_code = http_code; + + return SUCCESS; +} +static STATUS php_http_env_response_stream_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v) +{ + php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; + + if (stream_ctx->started || stream_ctx->finished) { + return FAILURE; + } + + memcpy(&stream_ctx->version, v, sizeof(stream_ctx->version)); + + return SUCCESS; +} +static STATUS php_http_env_response_stream_set_header_ex(php_http_env_response_t *r, zend_bool replace, const char *fmt, va_list argv) +{ + php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; + char *header_end, *header_str = NULL; + size_t header_len = 0; + zval *zheader, **zheader_ptr; + + if (stream_ctx->started || stream_ctx->finished) { + return FAILURE; + } + + header_len = vspprintf(&header_str, 0, fmt, argv); + + if (!(header_end = strchr(header_str, ':'))) { + efree(header_str); + return FAILURE; + } + + *header_end = '\0'; + + if (!replace && (SUCCESS == zend_hash_find(&stream_ctx->header, header_str, header_end - header_str + 1, (void *) &zheader_ptr))) { + convert_to_array(*zheader_ptr); + *header_end = ':'; + return add_next_index_stringl(*zheader_ptr, header_str, header_len, 0); + } else { + MAKE_STD_ZVAL(zheader); + ZVAL_STRINGL(zheader, header_str, header_len, 0); + + if (SUCCESS != zend_hash_update(&stream_ctx->header, header_str, header_end - header_str + 1, (void *) &zheader, sizeof(zval *), NULL)) { + zval_ptr_dtor(&zheader); + return FAILURE; + } + + *header_end = ':'; + return SUCCESS; + } +} +static STATUS php_http_env_response_stream_set_header(php_http_env_response_t *r, const char *fmt, ...) +{ + STATUS ret; + va_list argv; + + va_start(argv, fmt); + ret = php_http_env_response_stream_set_header_ex(r, 1, fmt, argv); + va_end(argv); + + return ret; +} +static STATUS php_http_env_response_stream_add_header(php_http_env_response_t *r, const char *fmt, ...) +{ + STATUS ret; + va_list argv; + + va_start(argv, fmt); + ret = php_http_env_response_stream_set_header_ex(r, 0, fmt, argv); + va_end(argv); + + return ret; +} +static STATUS php_http_env_response_stream_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len) +{ + php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; + + if (stream_ctx->started || stream_ctx->finished) { + return FAILURE; + } + + zend_hash_del(&stream_ctx->header, header_str, header_len + 1); + return SUCCESS; +} +static STATUS php_http_env_response_stream_write(php_http_env_response_t *r, const char *data_str, size_t data_len) +{ + php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; + TSRMLS_FETCH_FROM_CTX(r->ts); + + if (stream_ctx->finished) { + return FAILURE; + } + if (!stream_ctx->started) { + if (SUCCESS != php_http_env_response_stream_start(stream_ctx TSRMLS_CC)) { + return FAILURE; + } + } + + php_stream_write(stream_ctx->stream, data_str, data_len); + + return SUCCESS; +} +static STATUS php_http_env_response_stream_flush(php_http_env_response_t *r) +{ + php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; + TSRMLS_FETCH_FROM_CTX(r->ts); + + if (stream_ctx->finished) { + return FAILURE; + } + if (!stream_ctx->started) { + if (SUCCESS != php_http_env_response_stream_start(stream_ctx TSRMLS_CC)) { + return FAILURE; + } + } + + return php_stream_flush(stream_ctx->stream); +} +static STATUS php_http_env_response_stream_finish(php_http_env_response_t *r) +{ + php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; + TSRMLS_FETCH_FROM_CTX(r->ts); + + if (stream_ctx->finished) { + return FAILURE; + } + if (!stream_ctx->started) { + if (SUCCESS != php_http_env_response_stream_start(stream_ctx TSRMLS_CC)) { + return FAILURE; + } + } + + stream_ctx->finished = 1; + + return SUCCESS; +} + +static php_http_env_response_ops_t php_http_env_response_stream_ops = { + php_http_env_response_stream_init, + php_http_env_response_stream_dtor, + php_http_env_response_stream_get_status, + php_http_env_response_stream_set_status, + php_http_env_response_stream_set_protocol_version, + php_http_env_response_stream_set_header, + php_http_env_response_stream_add_header, + php_http_env_response_stream_del_header, + php_http_env_response_stream_write, + php_http_env_response_stream_flush, + php_http_env_response_stream_finish +}; + +php_http_env_response_ops_t *php_http_env_response_get_stream_ops(void) +{ + return &php_http_env_response_stream_ops; +} + +#define PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj) \ + do { \ + if (!obj->message) { \ + obj->message = php_http_message_init_env(NULL, PHP_HTTP_RESPONSE TSRMLS_CC); \ + } \ + } while (0) + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___construct, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, __construct) +{ + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + php_http_expect(obj->message = php_http_message_init_env(obj->message, PHP_HTTP_RESPONSE TSRMLS_CC), unexpected_val, return); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___invoke, 0, 0, 1) + ZEND_ARG_INFO(0, ob_string) + ZEND_ARG_INFO(0, ob_flags) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, __invoke) +{ + char *ob_str; + int ob_len; + long ob_flags = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &ob_str, &ob_len, &ob_flags)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj); + + if (obj->body || SUCCESS == php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, (void *) php_http_message_body_init(&obj->message->body, NULL TSRMLS_CC), (void *) &obj->body TSRMLS_CC)) { + php_http_message_body_append(obj->message->body, ob_str, ob_len); + RETURN_TRUE; + } + RETURN_FALSE; + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEnvRequest, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, env_request, http\\Message, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, setEnvRequest) +{ + zval *env_req = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O", &env_req, php_http_message_class_entry), invalid_arg, return); + + set_option(getThis(), ZEND_STRL("request"), IS_OBJECT, env_req, 0 TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentType, 0, 0, 1) + ZEND_ARG_INFO(0, content_type) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, setContentType) +{ + char *ct_str = NULL; + int ct_len = 0; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &ct_str, &ct_len), invalid_arg, return); + + set_option(getThis(), ZEND_STRL("contentType"), IS_STRING, ct_str, ct_len TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentDisposition, 0, 0, 1) + ZEND_ARG_ARRAY_INFO(0, disposition_params, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, setContentDisposition) +{ + zval *zdisposition; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &zdisposition), invalid_arg, return); + + zend_update_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("contentDisposition"), zdisposition TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentEncoding, 0, 0, 1) + ZEND_ARG_INFO(0, content_encoding) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, setContentEncoding) +{ + long ce; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ce), invalid_arg, return); + + set_option(getThis(), ZEND_STRL("contentEncoding"), IS_LONG, &ce, 0 TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setCacheControl, 0, 0, 1) + ZEND_ARG_INFO(0, cache_control) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, setCacheControl) +{ + char *cc_str = NULL; + int cc_len = 0; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &cc_str, &cc_len), invalid_arg, return); + + set_option(getThis(), ZEND_STRL("cacheControl"), IS_STRING, cc_str, cc_len TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setLastModified, 0, 0, 1) + ZEND_ARG_INFO(0, last_modified) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, setLastModified) +{ + long last_modified; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &last_modified), invalid_arg, return); + + set_option(getThis(), ZEND_STRL("lastModified"), IS_LONG, &last_modified, 0 TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByLastModified, 0, 0, 0) + ZEND_ARG_INFO(0, header_name) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, isCachedByLastModified) +{ + char *header_name_str = NULL; + int header_name_len = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) { + if (!header_name_str || !header_name_len) { + header_name_str = "If-Modified-Since"; + header_name_len = lenof("If-Modified-Since"); + } + + RETURN_LONG(php_http_env_is_response_cached_by_last_modified(getThis(), header_name_str, header_name_len, get_request(getThis() TSRMLS_CC) TSRMLS_CC)); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEtag, 0, 0, 1) + ZEND_ARG_INFO(0, etag) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, setEtag) +{ + char *etag_str = NULL; + int etag_len = 0; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &etag_str, &etag_len), invalid_arg, return); + + set_option(getThis(), ZEND_STRL("etag"), IS_STRING, etag_str, etag_len TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByEtag, 0, 0, 0) + ZEND_ARG_INFO(0, header_name) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, isCachedByEtag) +{ + char *header_name_str = NULL; + int header_name_len = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) { + if (!header_name_str || !header_name_len) { + header_name_str = "If-None-Match"; + header_name_len = lenof("If-None-Match"); + } + RETURN_LONG(php_http_env_is_response_cached_by_etag(getThis(), header_name_str, header_name_len, get_request(getThis() TSRMLS_CC) TSRMLS_CC)); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setThrottleRate, 0, 0, 1) + ZEND_ARG_INFO(0, chunk_size) + ZEND_ARG_INFO(0, delay) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, setThrottleRate) +{ + long chunk_size; + double delay = 1; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|d", &chunk_size, &delay), invalid_arg, return); + + set_option(getThis(), ZEND_STRL("throttleDelay"), IS_DOUBLE, &delay, 0 TSRMLS_CC); + set_option(getThis(), ZEND_STRL("throttleChunk"), IS_LONG, &chunk_size, 0 TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_send, 0, 0, 0) + ZEND_ARG_INFO(0, stream) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpEnvResponse, send) +{ + zval *zstream = NULL; + php_stream *s = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &zstream)) { + /* first flush the output layer to avoid conflicting headers and output; + * also, ob_start($thisEnvResponse) might have been called */ +#if PHP_VERSION_ID >= 50400 + php_output_end_all(TSRMLS_C); +#else + php_end_ob_buffers(1 TSRMLS_CC); +#endif + if (zstream) { + php_http_env_response_t *r; + + php_stream_from_zval(s, &zstream); + r = php_http_env_response_init(NULL, getThis(), php_http_env_response_get_stream_ops(), s TSRMLS_CC); + if (!r) { + RETURN_FALSE; + } + + RETVAL_BOOL(SUCCESS == php_http_env_response_send(r)); + php_http_env_response_free(&r); + } else { + php_http_env_response_t r; + + if (!php_http_env_response_init(&r, getThis(), NULL, NULL TSRMLS_CC)) { + RETURN_FALSE; + } + + RETVAL_BOOL(SUCCESS == php_http_env_response_send(&r)); + php_http_env_response_dtor(&r); + } + } +} + +static zend_function_entry php_http_env_response_methods[] = { + PHP_ME(HttpEnvResponse, __construct, ai_HttpEnvResponse___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpEnvResponse, __invoke, ai_HttpEnvResponse___invoke, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, setEnvRequest, ai_HttpEnvResponse_setEnvRequest, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, setContentType, ai_HttpEnvResponse_setContentType, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, setContentDisposition, ai_HttpEnvResponse_setContentDisposition, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, setContentEncoding, ai_HttpEnvResponse_setContentEncoding, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, setCacheControl, ai_HttpEnvResponse_setCacheControl, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, setLastModified, ai_HttpEnvResponse_setLastModified, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, isCachedByLastModified, ai_HttpEnvResponse_isCachedByLastModified, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, setEtag, ai_HttpEnvResponse_setEtag, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, isCachedByEtag, ai_HttpEnvResponse_isCachedByEtag, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, setThrottleRate, ai_HttpEnvResponse_setThrottleRate, ZEND_ACC_PUBLIC) + PHP_ME(HttpEnvResponse, send, ai_HttpEnvResponse_send, ZEND_ACC_PUBLIC) + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_env_response_class_entry; + +PHP_MINIT_FUNCTION(http_env_response) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Response", php_http_env_response_methods); + php_http_env_response_class_entry = zend_register_internal_class_ex(&ce, php_http_message_class_entry, NULL TSRMLS_CC); + + zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_ENCODING_NONE"), PHP_HTTP_CONTENT_ENCODING_NONE TSRMLS_CC); + zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_ENCODING_GZIP"), PHP_HTTP_CONTENT_ENCODING_GZIP TSRMLS_CC); + + zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_NO"), PHP_HTTP_CACHE_NO TSRMLS_CC); + zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_HIT"), PHP_HTTP_CACHE_HIT TSRMLS_CC); + zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_MISS"), PHP_HTTP_CACHE_MISS TSRMLS_CC); + + zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("request"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentType"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentDisposition"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentEncoding"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("cacheControl"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("etag"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("lastModified"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleDelay"), ZEND_ACC_PROTECTED TSRMLS_CC); + zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleChunk"), ZEND_ACC_PROTECTED TSRMLS_CC); + + return SUCCESS; +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_env_response.h b/php_http_env_response.h new file mode 100644 index 0000000..f79730f --- /dev/null +++ b/php_http_env_response.h @@ -0,0 +1,89 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_ENV_RESPONSE_H +#define PHP_HTTP_ENV_RESPONSE_H + +typedef struct php_http_env_response php_http_env_response_t; + +typedef struct php_http_env_response_ops { + STATUS (*init)(php_http_env_response_t *r, void *arg); + void (*dtor)(php_http_env_response_t *r); + long (*get_status)(php_http_env_response_t *r); + STATUS (*set_status)(php_http_env_response_t *r, long http_code); + STATUS (*set_protocol_version)(php_http_env_response_t *r, php_http_version_t *v); + STATUS (*set_header)(php_http_env_response_t *r, const char *fmt, ...); + STATUS (*add_header)(php_http_env_response_t *r, const char *fmt, ...); + STATUS (*del_header)(php_http_env_response_t *r, const char *header_str, size_t header_len); + STATUS (*write)(php_http_env_response_t *r, const char *data_str, size_t data_len); + STATUS (*flush)(php_http_env_response_t *r); + STATUS (*finish)(php_http_env_response_t *r); +} php_http_env_response_ops_t; + +PHP_HTTP_API php_http_env_response_ops_t *php_http_env_response_get_sapi_ops(void); +PHP_HTTP_API php_http_env_response_ops_t *php_http_env_response_get_stream_ops(void); + +struct php_http_env_response { + void *ctx; + php_http_env_response_ops_t *ops; + + php_http_buffer_t *buffer; + zval *options; + + struct { + size_t chunk; + double delay; + } throttle; + + struct { + php_http_range_status_t status; + HashTable values; + char boundary[32]; + } range; + + struct { + size_t length; + char *type; + char *encoding; + + php_http_encoding_stream_t *encoder; + } content; + + zend_bool done; + +#ifdef ZTS + void ***ts; +#endif +}; + +PHP_HTTP_API php_http_env_response_t *php_http_env_response_init(php_http_env_response_t *r, zval *options, php_http_env_response_ops_t *ops, void *ops_ctx TSRMLS_DC); +PHP_HTTP_API STATUS php_http_env_response_send(php_http_env_response_t *r); +PHP_HTTP_API void php_http_env_response_dtor(php_http_env_response_t *r); +PHP_HTTP_API void php_http_env_response_free(php_http_env_response_t **r); + +PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *options, const char *header_str, size_t header_len, php_http_message_t *request TSRMLS_DC); +PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *options, const char *header_str, size_t header_len, php_http_message_t *request TSRMLS_DC); + +PHP_HTTP_API zend_class_entry *php_http_env_response_class_entry; +PHP_MINIT_FUNCTION(http_env_response); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_etag.c b/php_http_etag.c new file mode 100644 index 0000000..72a7927 --- /dev/null +++ b/php_http_etag.c @@ -0,0 +1,127 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#ifdef PHP_HTTP_HAVE_HASH +# include "php_hash.h" +#endif + +#include +#include +#include + +php_http_etag_t *php_http_etag_init(const char *mode TSRMLS_DC) +{ + void *ctx; + php_http_etag_t *e; + + if (mode && (!strcasecmp(mode, "crc32b"))) { + ctx = emalloc(sizeof(uint)); + *((uint *) ctx) = ~0; + } else if (mode && !strcasecmp(mode, "sha1")) { + PHP_SHA1Init(ctx = emalloc(sizeof(PHP_SHA1_CTX))); + } else if (mode && !strcasecmp(mode, "md5")) { + PHP_MD5Init(ctx = emalloc(sizeof(PHP_MD5_CTX))); + } else { +#ifdef PHP_HTTP_HAVE_HASH + const php_hash_ops *eho = NULL; + + if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) { + ctx = emalloc(eho->context_size); + eho->hash_init(ctx); + } else +#endif + return NULL; + } + + e = emalloc(sizeof(*e)); + e->ctx = ctx; + e->mode = estrdup(mode); + TSRMLS_SET_CTX(e->ts); + + return e; +} + +char *php_http_etag_finish(php_http_etag_t *e) +{ + unsigned char digest[128] = {0}; + char *etag = NULL; + + if (!strcasecmp(e->mode, "crc32b")) { + unsigned char buf[4]; + + *((uint *) e->ctx) = ~*((uint *) e->ctx); + buf[0] = ((unsigned char *) e->ctx)[3]; + buf[1] = ((unsigned char *) e->ctx)[2]; + buf[2] = ((unsigned char *) e->ctx)[1]; + buf[3] = ((unsigned char *) e->ctx)[0]; + etag = php_http_etag_digest(buf, 4); + } else if ((!strcasecmp(e->mode, "sha1"))) { + PHP_SHA1Final(digest, e->ctx); + etag = php_http_etag_digest(digest, 20); + } else if ((!strcasecmp(e->mode, "md5"))) { + PHP_MD5Final(digest, e->ctx); + etag = php_http_etag_digest(digest, 16); + } else { +#ifdef PHP_HTTP_HAVE_HASH + const php_hash_ops *eho = NULL; + + if (e->mode && (eho = php_hash_fetch_ops(e->mode, strlen(e->mode)))) { + eho->hash_final(digest, e->ctx); + etag = php_http_etag_digest(digest, eho->digest_size); + } +#endif + } + + efree(e->ctx); + efree(e->mode); + efree(e); + + return etag; +} + +size_t php_http_etag_update(php_http_etag_t *e, const char *data_ptr, size_t data_len) +{ + if (!strcasecmp(e->mode, "crc32b")) { + uint i, c = *((uint *) e->ctx); + for (i = 0; i < data_len; ++i) { + CRC32(c, data_ptr[i]); + } + *((uint *) e->ctx) = c; + } else if ((!strcasecmp(e->mode, "sha1"))) { + PHP_SHA1Update(e->ctx, (const unsigned char *) data_ptr, data_len); + } else if ((!strcasecmp(e->mode, "md5"))) { + PHP_MD5Update(e->ctx, (const unsigned char *) data_ptr, data_len); + } else { +#ifdef PHP_HTTP_HAVE_HASH + const php_hash_ops *eho = NULL; + + if (e->mode && (eho = php_hash_fetch_ops(e->mode, strlen(e->mode)))) { + eho->hash_update(e->ctx, (const unsigned char *) data_ptr, data_len); + } +#endif + } + + return data_len; +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_etag.h b/php_http_etag.h new file mode 100644 index 0000000..dd0e3d1 --- /dev/null +++ b/php_http_etag.h @@ -0,0 +1,55 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_ETAG_H +#define PHP_HTTP_ETAG_H + +typedef struct php_http_etag { + void *ctx; + char *mode; + +#ifdef ZTS + void ***ts; +#endif +} php_http_etag_t; + +PHP_HTTP_API php_http_etag_t *php_http_etag_init(const char *mode TSRMLS_DC); +PHP_HTTP_API size_t php_http_etag_update(php_http_etag_t *e, const char *data_ptr, size_t data_len); +PHP_HTTP_API char *php_http_etag_finish(php_http_etag_t *e); + +static inline char *php_http_etag_digest(const unsigned char *digest, int len) +{ + static const char hexdigits[17] = "0123456789abcdef"; + int i; + char *hex = emalloc(len * 2 + 1); + char *ptr = hex; + + for (i = 0; i < len; ++i) { + *ptr++ = hexdigits[digest[i] >> 4]; + *ptr++ = hexdigits[digest[i] & 0xF]; + } + *ptr = '\0'; + + return hex; +} + +#endif /* PHP_HTTP_ETAG_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_exception.c b/php_http_exception.c new file mode 100644 index 0000000..00add62 --- /dev/null +++ b/php_http_exception.c @@ -0,0 +1,125 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#include + +#ifndef PHP_HTTP_DBG_EXCEPTIONS +# define PHP_HTTP_DBG_EXCEPTIONS 0 +#endif + +#if PHP_HTTP_DBG_EXCEPTIONS +static void php_http_exception_hook(zval *ex TSRMLS_DC) +{ + if (ex) { + zval *m = zend_read_property(Z_OBJCE_P(ex), ex, "message", lenof("message"), 0 TSRMLS_CC); + fprintf(stderr, "*** Threw exception '%s'\n", Z_STRVAL_P(m)); + } else { + fprintf(stderr, "*** Threw NULL exception\n"); + } +} +#endif + +zend_class_entry *php_http_exception_interface_class_entry; +zend_class_entry *php_http_exception_runtime_class_entry; +zend_class_entry *php_http_exception_unexpected_val_class_entry; +zend_class_entry *php_http_exception_bad_method_call_class_entry; +zend_class_entry *php_http_exception_invalid_arg_class_entry; +zend_class_entry *php_http_exception_bad_header_class_entry; +zend_class_entry *php_http_exception_bad_url_class_entry; +zend_class_entry *php_http_exception_bad_message_class_entry; +zend_class_entry *php_http_exception_bad_conversion_class_entry; +zend_class_entry *php_http_exception_bad_querystring_class_entry; + +PHP_MINIT_FUNCTION(http_exception) +{ + zend_class_entry *cep, ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "Exception", NULL); + php_http_exception_interface_class_entry = zend_register_internal_interface(&ce TSRMLS_CC); + + /* + * Would be great to only have a few exceptions and rather more identifying + * error codes, but zend_replace_error_handling() does not accept any codes. + */ + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "RuntimeException", NULL); + cep = zend_register_internal_class_ex(&ce, spl_ce_RuntimeException, NULL TSRMLS_CC); + zend_class_implements(cep TSRMLS_CC, 1, php_http_exception_interface_class_entry); + php_http_exception_runtime_class_entry = cep; + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "UnexpectedValueException", NULL); + cep = zend_register_internal_class_ex(&ce, spl_ce_UnexpectedValueException, NULL TSRMLS_CC); + zend_class_implements(cep TSRMLS_CC, 1, php_http_exception_interface_class_entry); + php_http_exception_unexpected_val_class_entry = cep; + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadMethodCallException", NULL); + cep = zend_register_internal_class_ex(&ce, spl_ce_BadMethodCallException, NULL TSRMLS_CC); + zend_class_implements(cep TSRMLS_CC, 1, php_http_exception_interface_class_entry); + php_http_exception_bad_method_call_class_entry = cep; + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "InvalidArgumentException", NULL); + cep = zend_register_internal_class_ex(&ce, spl_ce_InvalidArgumentException, NULL TSRMLS_CC); + zend_class_implements(cep TSRMLS_CC, 1, php_http_exception_interface_class_entry); + php_http_exception_invalid_arg_class_entry = cep; + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadHeaderException", NULL); + cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException, NULL TSRMLS_CC); + zend_class_implements(cep TSRMLS_CC, 1, php_http_exception_interface_class_entry); + php_http_exception_bad_header_class_entry = cep; + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadUrlException", NULL); + cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException, NULL TSRMLS_CC); + zend_class_implements(cep TSRMLS_CC, 1, php_http_exception_interface_class_entry); + php_http_exception_bad_url_class_entry = cep; + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadMessageException", NULL); + cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException, NULL TSRMLS_CC); + zend_class_implements(cep TSRMLS_CC, 1, php_http_exception_interface_class_entry); + php_http_exception_bad_message_class_entry = cep; + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadConversionException", NULL); + cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException, NULL TSRMLS_CC); + zend_class_implements(cep TSRMLS_CC, 1, php_http_exception_interface_class_entry); + php_http_exception_bad_conversion_class_entry = cep; + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadQueryStringException", NULL); + cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException, NULL TSRMLS_CC); + zend_class_implements(cep TSRMLS_CC, 1, php_http_exception_interface_class_entry); + php_http_exception_bad_querystring_class_entry = cep; + +#if PHP_HTTP_DBG_EXCEPTIONS + zend_throw_exception_hook = php_http_exception_hook; +#endif + + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_exception.h b/php_http_exception.h new file mode 100644 index 0000000..82a4b55 --- /dev/null +++ b/php_http_exception.h @@ -0,0 +1,55 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_EXCEPTION_H +#define PHP_HTTP_EXCEPTION_H + +/* short hand for zend_throw_exception_ex */ +#define php_http_throw(e, fmt, ...) \ + zend_throw_exception_ex(php_http_exception_ ##e## _class_entry, 0 TSRMLS_CC, fmt, __VA_ARGS__) + +/* wrap a call with replaced zend_error_handling */ +#define php_http_expect(test, e, fail) \ + do { \ + zend_error_handling __zeh; \ + zend_replace_error_handling(EH_THROW, php_http_exception_ ##e## _class_entry, &__zeh TSRMLS_CC); \ + if (!(test)) { \ + zend_restore_error_handling(&__zeh TSRMLS_CC); \ + fail; \ + } \ + zend_restore_error_handling(&__zeh TSRMLS_CC); \ + } while(0) + +PHP_HTTP_API zend_class_entry *php_http_exception_interface_class_entry; +PHP_HTTP_API zend_class_entry *php_http_exception_runtime_class_entry; +PHP_HTTP_API zend_class_entry *php_http_exception_unexpected_val_class_entry; +PHP_HTTP_API zend_class_entry *php_http_exception_bad_method_call_class_entry; +PHP_HTTP_API zend_class_entry *php_http_exception_invalid_arg_class_entry; +PHP_HTTP_API zend_class_entry *php_http_exception_bad_header_class_entry; +PHP_HTTP_API zend_class_entry *php_http_exception_bad_url_class_entry; +PHP_HTTP_API zend_class_entry *php_http_exception_bad_message_class_entry; +PHP_HTTP_API zend_class_entry *php_http_exception_bad_conversion_class_entry; +PHP_HTTP_API zend_class_entry *php_http_exception_bad_querystring_class_entry; + +PHP_MINIT_FUNCTION(http_exception); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_exception_object.h b/php_http_exception_object.h deleted file mode 100644 index df89e4f..0000000 --- a/php_http_exception_object.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_EXCEPTION_OBJECT_H -#define PHP_HTTP_EXCEPTION_OBJECT_H -#ifdef ZEND_ENGINE_2 - -#include "zend_exceptions.h" - -PHP_MINIT_FUNCTION(http_exception_object); - -#define HTTP_EX_DEF_CE http_exception_object_ce -#define HTTP_EX_CE(name) http_ ##name## _exception_object_ce - -extern zend_class_entry *http_exception_object_ce; -extern zend_class_entry *HTTP_EX_CE(runtime); -extern zend_class_entry *HTTP_EX_CE(header); -extern zend_class_entry *HTTP_EX_CE(malformed_headers); -extern zend_class_entry *HTTP_EX_CE(request_method); -extern zend_class_entry *HTTP_EX_CE(message_type); -extern zend_class_entry *HTTP_EX_CE(invalid_param); -extern zend_class_entry *HTTP_EX_CE(encoding); -extern zend_class_entry *HTTP_EX_CE(request); -extern zend_class_entry *HTTP_EX_CE(request_pool); -extern zend_class_entry *HTTP_EX_CE(socket); -extern zend_class_entry *HTTP_EX_CE(response); -extern zend_class_entry *HTTP_EX_CE(url); -extern zend_function_entry http_exception_object_fe[]; - -#define http_exception_get_default _http_exception_get_default -extern zend_class_entry *_http_exception_get_default(); - -#define http_exception_get_for_code(c) _http_exception_get_for_code(c) -extern zend_class_entry *_http_exception_get_for_code(long code); - -PHP_METHOD(HttpException, __toString); - -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_filter.c b/php_http_filter.c new file mode 100644 index 0000000..f0ba862 --- /dev/null +++ b/php_http_filter.c @@ -0,0 +1,453 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#ifndef DBG_FILTER +# define DBG_FILTER 0 +#endif + +PHP_MINIT_FUNCTION(http_filter) +{ + php_stream_filter_register_factory("http.*", &php_http_filter_factory TSRMLS_CC); + return SUCCESS; +} + +#define PHP_HTTP_FILTER_PARAMS \ + php_stream *stream, \ + php_stream_filter *this, \ + php_stream_bucket_brigade *buckets_in, \ + php_stream_bucket_brigade *buckets_out, \ + size_t *bytes_consumed, int flags \ + TSRMLS_DC +#define PHP_HTTP_FILTER_OP(filter) \ + http_filter_op_ ##filter +#define PHP_HTTP_FILTER_OPS(filter) \ + php_stream_filter_ops PHP_HTTP_FILTER_OP(filter) +#define PHP_HTTP_FILTER_DTOR(filter) \ + http_filter_ ##filter## _dtor +#define PHP_HTTP_FILTER_DESTRUCTOR(filter) \ + void PHP_HTTP_FILTER_DTOR(filter)(php_stream_filter *this TSRMLS_DC) +#define PHP_HTTP_FILTER_FUNC(filter) \ + http_filter_ ##filter +#define PHP_HTTP_FILTER_FUNCTION(filter) \ + php_stream_filter_status_t PHP_HTTP_FILTER_FUNC(filter)(PHP_HTTP_FILTER_PARAMS) +#define PHP_HTTP_FILTER_BUFFER(filter) \ + http_filter_ ##filter## _buffer + +#define PHP_HTTP_FILTER_IS_CLOSING(stream, flags) \ + ( (flags & PSFS_FLAG_FLUSH_CLOSE) \ + || php_stream_eof(stream) \ + || ((stream->ops == &php_stream_temp_ops || stream->ops == &php_stream_memory_ops) && stream->eof) \ + ) + +#define NEW_BUCKET(data, length) \ + { \ + char *__data; \ + php_stream_bucket *__buck; \ + \ + __data = pemalloc(length, this->is_persistent); \ + if (!__data) { \ + return PSFS_ERR_FATAL; \ + } \ + memcpy(__data, data, length); \ + \ + __buck = php_stream_bucket_new(stream, __data, length, 1, this->is_persistent TSRMLS_CC); \ + if (!__buck) { \ + pefree(__data, this->is_persistent); \ + return PSFS_ERR_FATAL; \ + } \ + \ + php_stream_bucket_append(buckets_out, __buck TSRMLS_CC); \ + } + +typedef struct _http_chunked_decode_filter_buffer_t { + php_http_buffer_t buffer; + ulong hexlen; +} PHP_HTTP_FILTER_BUFFER(chunked_decode); + +typedef php_http_encoding_stream_t PHP_HTTP_FILTER_BUFFER(zlib); + +static PHP_HTTP_FILTER_FUNCTION(chunked_decode) +{ + int out_avail = 0; + php_stream_bucket *ptr, *nxt; + PHP_HTTP_FILTER_BUFFER(chunked_decode) *buffer = (PHP_HTTP_FILTER_BUFFER(chunked_decode) *) (this->abstract); + + if (bytes_consumed) { + *bytes_consumed = 0; + } + + /* fetch available bucket data */ + for (ptr = buckets_in->head; ptr; ptr = nxt) { + if (bytes_consumed) { + *bytes_consumed += ptr->buflen; + } + + if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(PHP_HTTP_BUFFER(buffer), ptr->buf, ptr->buflen)) { + return PSFS_ERR_FATAL; + } + + nxt = ptr->next; + php_stream_bucket_unlink(ptr TSRMLS_CC); + php_stream_bucket_delref(ptr TSRMLS_CC); + } + + if (!php_http_buffer_fix(PHP_HTTP_BUFFER(buffer))) { + return PSFS_ERR_FATAL; + } + + /* we have data in our buffer */ + while (PHP_HTTP_BUFFER(buffer)->used) { + + /* we already know the size of the chunk and are waiting for data */ + if (buffer->hexlen) { + + /* not enough data buffered */ + if (PHP_HTTP_BUFFER(buffer)->used < buffer->hexlen) { + + /* flush anyway? */ + if (flags & PSFS_FLAG_FLUSH_INC) { + + /* flush all data (should only be chunk data) */ + out_avail = 1; + NEW_BUCKET(PHP_HTTP_BUFFER(buffer)->data, PHP_HTTP_BUFFER(buffer)->used); + + /* waiting for less data now */ + buffer->hexlen -= PHP_HTTP_BUFFER(buffer)->used; + /* no more buffered data */ + php_http_buffer_reset(PHP_HTTP_BUFFER(buffer)); + /* break */ + } + + /* we have too less data and don't need to flush */ + else { + break; + } + } + + /* we seem to have all data of the chunk */ + else { + out_avail = 1; + NEW_BUCKET(PHP_HTTP_BUFFER(buffer)->data, buffer->hexlen); + + /* remove outgoing data from the buffer */ + php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, buffer->hexlen); + /* reset hexlen */ + buffer->hexlen = 0; + /* continue */ + } + } + + /* we don't know the length of the chunk yet */ + else { + size_t off = 0; + + /* ignore preceeding CRLFs (too loose?) */ + while (off < PHP_HTTP_BUFFER(buffer)->used && ( + PHP_HTTP_BUFFER(buffer)->data[off] == '\n' || + PHP_HTTP_BUFFER(buffer)->data[off] == '\r')) { + ++off; + } + if (off) { + php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, off); + } + + /* still data there? */ + if (PHP_HTTP_BUFFER(buffer)->used) { + int eollen; + const char *eolstr; + + /* we need eol, so we can be sure we have all hex digits */ + php_http_buffer_fix(PHP_HTTP_BUFFER(buffer)); + if ((eolstr = php_http_locate_bin_eol(PHP_HTTP_BUFFER(buffer)->data, PHP_HTTP_BUFFER(buffer)->used, &eollen))) { + char *stop = NULL; + + /* read in chunk size */ + buffer->hexlen = strtoul(PHP_HTTP_BUFFER(buffer)->data, &stop, 16); + + /* if strtoul() stops at the beginning of the buffered data + there's something oddly wrong, i.e. bad input */ + if (stop == PHP_HTTP_BUFFER(buffer)->data) { + return PSFS_ERR_FATAL; + } + + /* cut out */ + php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, eolstr + eollen - PHP_HTTP_BUFFER(buffer)->data); + /* buffer->hexlen is 0 now or contains the size of the next chunk */ + if (!buffer->hexlen) { + php_stream_notify_info(stream->context, PHP_STREAM_NOTIFY_COMPLETED, NULL, 0); + break; + } + /* continue */ + } else { + /* we have not enough data buffered to read in chunk size */ + break; + } + } + /* break */ + } + } + + /* flush before close, but only if we are already waiting for more data */ + if (PHP_HTTP_FILTER_IS_CLOSING(stream, flags) && buffer->hexlen && PHP_HTTP_BUFFER(buffer)->used) { + out_avail = 1; + NEW_BUCKET(PHP_HTTP_BUFFER(buffer)->data, PHP_HTTP_BUFFER(buffer)->used); + php_http_buffer_reset(PHP_HTTP_BUFFER(buffer)); + buffer->hexlen = 0; + } + + return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME; +} + +static PHP_HTTP_FILTER_DESTRUCTOR(chunked_decode) +{ + PHP_HTTP_FILTER_BUFFER(chunked_decode) *b = (PHP_HTTP_FILTER_BUFFER(chunked_decode) *) (this->abstract); + + php_http_buffer_dtor(PHP_HTTP_BUFFER(b)); + pefree(b, this->is_persistent); +} + +static PHP_HTTP_FILTER_FUNCTION(chunked_encode) +{ + php_http_buffer_t buf; + php_stream_bucket *ptr, *nxt; + + if (bytes_consumed) { + *bytes_consumed = 0; + } + + /* new data available? */ + php_http_buffer_init(&buf); + + /* fetch available bucket data */ + for (ptr = buckets_in->head; ptr; ptr = nxt) { + if (bytes_consumed) { + *bytes_consumed += ptr->buflen; + } +#if DBG_FILTER + fprintf(stderr, "update: chunked (-> %zu) (w: %zu, r: %zu)\n", ptr->buflen, stream->writepos, stream->readpos); +#endif + + nxt = ptr->next; + php_stream_bucket_unlink(ptr TSRMLS_CC); + php_http_buffer_appendf(&buf, "%lx" PHP_HTTP_CRLF, (long unsigned int) ptr->buflen); + php_http_buffer_append(&buf, ptr->buf, ptr->buflen); + php_http_buffer_appends(&buf, PHP_HTTP_CRLF); + + /* pass through */ + NEW_BUCKET(buf.data, buf.used); + /* reset */ + php_http_buffer_reset(&buf); + php_stream_bucket_delref(ptr TSRMLS_CC); + } + + /* free buffer */ + php_http_buffer_dtor(&buf); + + /* terminate with "0" */ + if (PHP_HTTP_FILTER_IS_CLOSING(stream, flags)) { +#if DBG_FILTER + fprintf(stderr, "finish: chunked\n"); +#endif + + NEW_BUCKET("0" PHP_HTTP_CRLF PHP_HTTP_CRLF, lenof("0" PHP_HTTP_CRLF PHP_HTTP_CRLF)); + } + + return PSFS_PASS_ON; +} + +static PHP_HTTP_FILTER_OPS(chunked_decode) = { + PHP_HTTP_FILTER_FUNC(chunked_decode), + PHP_HTTP_FILTER_DTOR(chunked_decode), + "http.chunked_decode" +}; + +static PHP_HTTP_FILTER_OPS(chunked_encode) = { + PHP_HTTP_FILTER_FUNC(chunked_encode), + NULL, + "http.chunked_encode" +}; + +static PHP_HTTP_FILTER_FUNCTION(zlib) +{ + php_stream_bucket *ptr, *nxt; + PHP_HTTP_FILTER_BUFFER(zlib) *buffer = (PHP_HTTP_FILTER_BUFFER(zlib) *) this->abstract; + + if (bytes_consumed) { + *bytes_consumed = 0; + } + + /* fetch available bucket data */ + for (ptr = buckets_in->head; ptr; ptr = nxt) { + char *encoded = NULL; + size_t encoded_len = 0; + + if (bytes_consumed) { + *bytes_consumed += ptr->buflen; + } + +#if DBG_FILTER + fprintf(stderr, "bucket: b=%p p=%p p=%p\n", ptr->brigade, ptr->prev, ptr->next); +#endif + + nxt = ptr->next; + php_stream_bucket_unlink(ptr TSRMLS_CC); + php_http_encoding_stream_update(buffer, ptr->buf, ptr->buflen, &encoded, &encoded_len); + +#if DBG_FILTER + fprintf(stderr, "update: deflate (-> %zu) (w: %zu, r: %zu)\n", encoded_len, stream->writepos, stream->readpos); +#endif + + if (encoded) { + if (encoded_len) { + NEW_BUCKET(encoded, encoded_len); + } + efree(encoded); + } + php_stream_bucket_delref(ptr TSRMLS_CC); + } + + /* flush & close */ + if (flags & PSFS_FLAG_FLUSH_INC) { + char *encoded = NULL; + size_t encoded_len = 0; + + php_http_encoding_stream_flush(buffer, &encoded, &encoded_len); + +#if DBG_FILTER + fprintf(stderr, "flush: deflate (-> %zu)\n", encoded_len); +#endif + + if (encoded) { + if (encoded_len) { + NEW_BUCKET(encoded, encoded_len); + } + efree(encoded); + } + } + + if (PHP_HTTP_FILTER_IS_CLOSING(stream, flags)) { + char *encoded = NULL; + size_t encoded_len = 0; + + php_http_encoding_stream_finish(buffer, &encoded, &encoded_len); + +#if DBG_FILTER + fprintf(stderr, "finish: deflate (-> %zu)\n", encoded_len); +#endif + + if (encoded) { + if (encoded_len) { + NEW_BUCKET(encoded, encoded_len); + } + efree(encoded); + } + } + + return PSFS_PASS_ON; +} +static PHP_HTTP_FILTER_DESTRUCTOR(zlib) +{ + PHP_HTTP_FILTER_BUFFER(zlib) *buffer = (PHP_HTTP_FILTER_BUFFER(zlib) *) this->abstract; + php_http_encoding_stream_free(&buffer); +} + +static PHP_HTTP_FILTER_OPS(deflate) = { + PHP_HTTP_FILTER_FUNC(zlib), + PHP_HTTP_FILTER_DTOR(zlib), + "http.deflate" +}; + +static PHP_HTTP_FILTER_OPS(inflate) = { + PHP_HTTP_FILTER_FUNC(zlib), + PHP_HTTP_FILTER_DTOR(zlib), + "http.inflate" +}; + +static php_stream_filter *http_filter_create(const char *name, zval *params, int p TSRMLS_DC) +{ + zval **tmp = ¶ms; + php_stream_filter *f = NULL; + int flags = p ? PHP_HTTP_ENCODING_STREAM_PERSISTENT : 0; + + if (params) { + switch (Z_TYPE_P(params)) { + case IS_ARRAY: + case IS_OBJECT: + if (SUCCESS != zend_hash_find(HASH_OF(params), "flags", sizeof("flags"), (void *) &tmp)) { + break; + } + /* no break */ + default: + { + zval *num = php_http_ztyp(IS_LONG, *tmp); + + flags |= (Z_LVAL_P(num) & 0x0fffffff); + zval_ptr_dtor(&num); + + } + break; + } + } + + if (!strcasecmp(name, "http.chunked_decode")) { + PHP_HTTP_FILTER_BUFFER(chunked_decode) *b = NULL; + + if ((b = pecalloc(1, sizeof(PHP_HTTP_FILTER_BUFFER(chunked_decode)), p))) { + php_http_buffer_init_ex(PHP_HTTP_BUFFER(b), 4096, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0); + if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(chunked_decode), b, p))) { + pefree(b, p); + } + } + } else + + if (!strcasecmp(name, "http.chunked_encode")) { + f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(chunked_encode), NULL, p); + } else + + if (!strcasecmp(name, "http.inflate")) { + PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL; + + if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_inflate_ops(), flags TSRMLS_CC))) { + if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(inflate), b, p))) { + php_http_encoding_stream_free(&b); + } + } + } else + + if (!strcasecmp(name, "http.deflate")) { + PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL; + + if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), flags TSRMLS_CC))) { + if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(deflate), b, p))) { + php_http_encoding_stream_free(&b); + } + } + } + + return f; +} + +php_stream_filter_factory php_http_filter_factory = { + http_filter_create +}; + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_filter_api.h b/php_http_filter.h similarity index 78% rename from php_http_filter_api.h rename to php_http_filter.h index d1322a1..b2b8682 100644 --- a/php_http_filter_api.h +++ b/php_http_filter.h @@ -6,20 +6,16 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | + | Copyright (c) 2004-2013, Michael Wallner | +--------------------------------------------------------------------+ */ -/* $Id$ */ +#ifndef PHP_HTTP_FILTER_H +#define PHP_HTTP_FILTER_H -#ifndef PHP_HTTP_FILTER_API_H -#define PHP_HTTP_FILTER_API_H -#ifdef ZEND_ENGINE_2 - -extern php_stream_filter_factory http_filter_factory; +PHP_HTTP_API php_stream_filter_factory php_http_filter_factory; PHP_MINIT_FUNCTION(http_filter); -#endif #endif /* diff --git a/php_http_header.c b/php_http_header.c new file mode 100644 index 0000000..08e643b --- /dev/null +++ b/php_http_header.c @@ -0,0 +1,388 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +STATUS php_http_header_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data TSRMLS_DC) +{ + php_http_header_parser_t ctx; + php_http_buffer_t buf; + php_http_header_parser_state_t rs; + + if (!php_http_buffer_from_string_ex(&buf, header, length)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not allocate buffer"); + return FAILURE; + } + + if (!php_http_header_parser_init(&ctx TSRMLS_CC)) { + php_http_buffer_dtor(&buf); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize header parser"); + return FAILURE; + } + + rs = php_http_header_parser_parse(&ctx, &buf, PHP_HTTP_HEADER_PARSER_CLEANUP, headers, callback_func, callback_data); + php_http_header_parser_dtor(&ctx); + php_http_buffer_dtor(&buf); + + if (rs == PHP_HTTP_HEADER_PARSER_STATE_FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse headers"); + return FAILURE; + } + + return SUCCESS; +} + +void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg TSRMLS_DC) +{ + HashPosition pos1, pos2; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + zval **header, **single_header; + + FOREACH_HASH_KEYVAL(pos1, headers, key, header) { + if (key.type == HASH_KEY_IS_STRING) { + if (key.len == sizeof("Set-Cookie") && !strcasecmp(key.str, "Set-Cookie") && Z_TYPE_PP(header) == IS_ARRAY) { + FOREACH_VAL(pos2, *header, single_header) { + if (Z_TYPE_PP(single_header) == IS_ARRAY) { + php_http_cookie_list_t *cookie = php_http_cookie_list_from_struct(NULL, *single_header TSRMLS_CC); + + if (cookie) { + char *buf; + size_t len; + + php_http_cookie_list_to_string(cookie, &buf, &len); + cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", buf); + php_http_cookie_list_free(&cookie); + efree(buf); + } + } else { + zval *strval = php_http_header_value_to_string(*single_header TSRMLS_CC); + + cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", Z_STRVAL_P(strval)); + zval_ptr_dtor(&strval); + } + } + } else { + zval *strval = php_http_header_value_to_string(*header TSRMLS_CC); + + cb(cb_arg, crlf ? "%s: %s" PHP_HTTP_CRLF : "%s: %s", key.str, Z_STRVAL_P(strval)); + zval_ptr_dtor(&strval); + } + } + } +} + +void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers TSRMLS_DC) +{ + php_http_header_to_callback(headers, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str TSRMLS_CC); +} + +zval *php_http_header_value_to_string(zval *header TSRMLS_DC) +{ + zval *ret; + + if (Z_TYPE_P(header) == IS_BOOL) { + MAKE_STD_ZVAL(ret); + ZVAL_STRING(ret, Z_BVAL_P(header) ? "true" : "false", 1); + } else if (Z_TYPE_P(header) == IS_ARRAY) { + zval **val; + HashPosition pos; + php_http_buffer_t str; + + php_http_buffer_init(&str); + MAKE_STD_ZVAL(ret); + FOREACH_VAL(pos,header, val) { + zval *strval = php_http_header_value_to_string(*val TSRMLS_CC); + + php_http_buffer_appendf(&str, str.used ? ", %s":"%s", Z_STRVAL_P(strval)); + zval_ptr_dtor(&strval); + } + php_http_buffer_fix(&str); + ZVAL_STRINGL(ret, str.data, str.used, 0); + } else { + ret = php_http_zsep(1, IS_STRING, header); + } + + return ret; +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader___construct, 0, 0, 0) + ZEND_ARG_INFO(0, name) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpHeader, __construct) +{ + char *name_str = NULL, *value_str = NULL; + int name_len = 0, value_len = 0; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return); + + if (name_str && name_len) { + char *pretty_str = estrndup(name_str, name_len); + zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("name"), php_http_pretty_key(pretty_str, name_len, 1, 1), name_len TSRMLS_CC); + efree(pretty_str); + } + if (value_str && value_len) { + zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("value"), value_str, value_len TSRMLS_CC); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_serialize, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpHeader, serialize) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_buffer_t buf; + zval *zname, *zvalue; + + php_http_buffer_init(&buf); + zname = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("name"), 0 TSRMLS_CC)); + php_http_buffer_append(&buf, Z_STRVAL_P(zname), Z_STRLEN_P(zname)); + zval_ptr_dtor(&zname); + zvalue = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0 TSRMLS_CC)); + if (Z_STRLEN_P(zvalue)) { + php_http_buffer_appends(&buf, ": "); + php_http_buffer_append(&buf, Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue)); + } else { + php_http_buffer_appends(&buf, ":"); + } + zval_ptr_dtor(&zvalue); + + RETURN_PHP_HTTP_BUFFER_VAL(&buf); + } + RETURN_EMPTY_STRING(); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_unserialize, 0, 0, 1) + ZEND_ARG_INFO(0, serialized) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpHeader, unserialize) +{ + char *serialized_str; + int serialized_len; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &serialized_str, &serialized_len)) { + HashTable ht; + + zend_hash_init(&ht, 1, NULL, ZVAL_PTR_DTOR, 0); + if (SUCCESS == php_http_header_parse(serialized_str, serialized_len, &ht, NULL, NULL TSRMLS_CC)) { + if (zend_hash_num_elements(&ht)) { + zval **val, *cpy; + char *str; + uint len; + ulong idx; + + zend_hash_internal_pointer_reset(&ht); + switch (zend_hash_get_current_key_ex(&ht, &str, &len, &idx, 0, NULL)) { + case HASH_KEY_IS_STRING: + zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("name"), str, len - 1 TSRMLS_CC); + break; + case HASH_KEY_IS_LONG: + zend_update_property_long(php_http_header_class_entry, getThis(), ZEND_STRL("name"), idx TSRMLS_CC); + break; + default: + break; + } + zend_hash_get_current_data(&ht, (void *) &val); + cpy = php_http_zsep(1, IS_STRING, *val); + zend_update_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), cpy TSRMLS_CC); + zval_ptr_dtor(&cpy); + } + } + zend_hash_destroy(&ht); + } + +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_match, 0, 0, 1) + ZEND_ARG_INFO(0, value) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpHeader, match) +{ + char *val_str; + int val_len; + long flags = PHP_HTTP_MATCH_LOOSE; + zval *zvalue; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &val_str, &val_len, &flags)) { + return; + } + + zvalue = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0 TSRMLS_CC)); + RETVAL_BOOL(php_http_match(Z_STRVAL_P(zvalue), val_str, flags)); + zval_ptr_dtor(&zvalue); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_negotiate, 0, 0, 1) + ZEND_ARG_INFO(0, supported) + ZEND_ARG_INFO(1, result) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpHeader, negotiate) +{ + HashTable *supported, *rs; + zval *zname, *zvalue, *rs_array = NULL; + char *sep_str = NULL; + size_t sep_len = 0; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) { + return; + } + if (rs_array) { + zval_dtor(rs_array); + array_init(rs_array); + } + + zname = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("name"), 0 TSRMLS_CC)); + if (!strcasecmp(Z_STRVAL_P(zname), "Accept")) { + sep_str = "/"; + sep_len = 1; + } else if (!strcasecmp(Z_STRVAL_P(zname), "Accept-Language")) { + sep_str = "-"; + sep_len = 1; + } + zval_ptr_dtor(&zname); + + zvalue = php_http_ztyp(IS_STRING, zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0 TSRMLS_CC)); + if ((rs = php_http_negotiate(Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue), supported, sep_str, sep_len TSRMLS_CC))) { + PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array); + } else { + PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); + } + zval_ptr_dtor(&zvalue); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_getParams, 0, 0, 0) + ZEND_ARG_INFO(0, param_sep) + ZEND_ARG_INFO(0, arg_sep) + ZEND_ARG_INFO(0, val_sep) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpHeader, getParams) +{ + zval zctor, *zparams_obj, **zargs = NULL; + + INIT_PZVAL(&zctor); + ZVAL_STRINGL(&zctor, "__construct", lenof("__construct"), 0); + + MAKE_STD_ZVAL(zparams_obj); + object_init_ex(zparams_obj, php_http_params_class_entry); + + zargs = (zval **) ecalloc(ZEND_NUM_ARGS()+1, sizeof(zval *)); + zargs[0] = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("value"), 0 TSRMLS_CC); + if (ZEND_NUM_ARGS()) { + zend_get_parameters_array(ZEND_NUM_ARGS(), ZEND_NUM_ARGS(), &zargs[1]); + } + + if (SUCCESS == call_user_function(NULL, &zparams_obj, &zctor, return_value, ZEND_NUM_ARGS()+1, zargs TSRMLS_CC)) { + RETVAL_ZVAL(zparams_obj, 0, 1); + } + + if (zargs) { + efree(zargs); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_parse, 0, 0, 1) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, header_class) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpHeader, parse) +{ + char *header_str; + int header_len; + zend_class_entry *ce = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C", &header_str, &header_len, &ce)) { + array_init(return_value); + + if (SUCCESS != php_http_header_parse(header_str, header_len, Z_ARRVAL_P(return_value), NULL, NULL TSRMLS_CC)) { + zval_dtor(return_value); + RETURN_FALSE; + } else { + if (ce && instanceof_function(ce, php_http_header_class_entry TSRMLS_CC)) { + HashPosition pos; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + zval **val; + + FOREACH_KEYVAL(pos, return_value, key, val) { + zval *zho, *zkey, *zvalue; + + Z_ADDREF_PP(val); + zvalue = *val; + + MAKE_STD_ZVAL(zkey); + if (key.type == HASH_KEY_IS_LONG) { + ZVAL_LONG(zkey, key.num); + } else { + ZVAL_STRINGL(zkey, key.str, key.len - 1, 1); + } + + MAKE_STD_ZVAL(zho); + object_init_ex(zho, ce); + zend_call_method_with_2_params(&zho, ce, NULL, "__construct", NULL, zkey, zvalue); + + if (key.type == HASH_KEY_IS_LONG) { + zend_hash_index_update(Z_ARRVAL_P(return_value), key.num, (void *) &zho, sizeof(zval *), NULL); + } else { + zend_hash_update(Z_ARRVAL_P(return_value), key.str, key.len, (void *) &zho, sizeof(zval *), NULL); + } + + zval_ptr_dtor(&zvalue); + zval_ptr_dtor(&zkey); + } + } + } + } +} + +static zend_function_entry php_http_header_methods[] = { + PHP_ME(HttpHeader, __construct, ai_HttpHeader___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpHeader, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC) + ZEND_MALIAS(HttpHeader, __toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC) + ZEND_MALIAS(HttpHeader, toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC) + PHP_ME(HttpHeader, unserialize, ai_HttpHeader_unserialize, ZEND_ACC_PUBLIC) + PHP_ME(HttpHeader, match, ai_HttpHeader_match, ZEND_ACC_PUBLIC) + PHP_ME(HttpHeader, negotiate, ai_HttpHeader_negotiate, ZEND_ACC_PUBLIC) + PHP_ME(HttpHeader, getParams, ai_HttpHeader_getParams, ZEND_ACC_PUBLIC) + PHP_ME(HttpHeader, parse, ai_HttpHeader_parse, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_header_class_entry; + +PHP_MINIT_FUNCTION(http_header) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "Header", php_http_header_methods); + php_http_header_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + zend_class_implements(php_http_header_class_entry TSRMLS_CC, 1, zend_ce_serializable); + zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_LOOSE"), PHP_HTTP_MATCH_LOOSE TSRMLS_CC); + zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_CASE"), PHP_HTTP_MATCH_CASE TSRMLS_CC); + zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_WORD"), PHP_HTTP_MATCH_WORD TSRMLS_CC); + zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_FULL"), PHP_HTTP_MATCH_FULL TSRMLS_CC); + zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_STRICT"), PHP_HTTP_MATCH_STRICT TSRMLS_CC); + zend_declare_property_null(php_http_header_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_http_header_class_entry, ZEND_STRL("value"), ZEND_ACC_PUBLIC TSRMLS_CC); + + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_querystring_api.h b/php_http_header.h similarity index 51% rename from php_http_querystring_api.h rename to php_http_header.h index 2a366b3..2c0d2e8 100644 --- a/php_http_querystring_api.h +++ b/php_http_header.h @@ -6,25 +6,24 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | + | Copyright (c) 2004-2013, Michael Wallner | +--------------------------------------------------------------------+ */ -/* $Id$ */ +#ifndef PHP_HTTP_HEADERS_H +#define PHP_HTTP_HEADERS_H -#ifndef PHP_HTTP_QUERYSTRING_API_H -#define PHP_HTTP_QUERYSTRING_API_H +#include "php_http_info.h" -#ifdef HTTP_HAVE_ICONV -#define http_querystring_xlate(a, p, ie, oe) _http_querystring_xlate((a), (p), (ie), (oe) TSRMLS_CC) -PHP_HTTP_API int _http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC); -#endif +PHP_HTTP_API STATUS php_http_header_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data TSRMLS_DC); + +PHP_HTTP_API void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg TSRMLS_DC); +PHP_HTTP_API void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers TSRMLS_DC); -#define http_querystring_update(qa, qs) _http_querystring_update((qa), (qs) TSRMLS_CC) -PHP_HTTP_API void _http_querystring_update(zval *qarray, zval *qstring TSRMLS_DC); +PHP_HTTP_API zval *php_http_header_value_to_string(zval *header TSRMLS_DC); -#define http_querystring_modify(q, p) _http_querystring_modify((q), (p) TSRMLS_CC) -PHP_HTTP_API int _http_querystring_modify(zval *qarray, zval *params TSRMLS_DC); +PHP_HTTP_API zend_class_entry *php_http_header_class_entry; +PHP_MINIT_FUNCTION(http_header); #endif @@ -36,3 +35,4 @@ PHP_HTTP_API int _http_querystring_modify(zval *qarray, zval *params TSRMLS_DC); * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ + diff --git a/php_http_header_parser.c b/php_http_header_parser.c new file mode 100644 index 0000000..e7fc886 --- /dev/null +++ b/php_http_header_parser.c @@ -0,0 +1,256 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +typedef struct php_http_header_parser_state_spec { + php_http_header_parser_state_t state; + unsigned need_data:1; +} php_http_header_parser_state_spec_t; + +static const php_http_header_parser_state_spec_t php_http_header_parser_states[] = { + {PHP_HTTP_HEADER_PARSER_STATE_START, 1}, + {PHP_HTTP_HEADER_PARSER_STATE_KEY, 1}, + {PHP_HTTP_HEADER_PARSER_STATE_VALUE, 1}, + {PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX, 1}, + {PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE, 0}, + {PHP_HTTP_HEADER_PARSER_STATE_DONE, 0} +}; + +php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser TSRMLS_DC) +{ + if (!parser) { + parser = emalloc(sizeof(*parser)); + } + memset(parser, 0, sizeof(*parser)); + + TSRMLS_SET_CTX(parser->ts); + + return parser; +} + +php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...) +{ + va_list va_args; + unsigned i; + php_http_header_parser_state_t state = 0; + + va_start(va_args, argc); + for (i = 0; i < argc; ++i) { + state = va_arg(va_args, php_http_header_parser_state_t); + zend_stack_push(&parser->stack, &state, sizeof(state)); + } + va_end(va_args); + + return state; +} + +php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser) +{ + php_http_header_parser_state_t *state; + + if (SUCCESS == zend_stack_top(&parser->stack, (void *) &state)) { + return *state; + } + return PHP_HTTP_HEADER_PARSER_STATE_START; +} + +php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser) +{ + php_http_header_parser_state_t state, *state_ptr; + if (SUCCESS == zend_stack_top(&parser->stack, (void *) &state_ptr)) { + state = *state_ptr; + zend_stack_del_top(&parser->stack); + return state; + } + return PHP_HTTP_HEADER_PARSER_STATE_START; +} + +void php_http_header_parser_dtor(php_http_header_parser_t *parser) +{ + zend_stack_destroy(&parser->stack); + php_http_info_dtor(&parser->info); + STR_FREE(parser->_key.str); + STR_FREE(parser->_val.str); +} + +void php_http_header_parser_free(php_http_header_parser_t **parser) +{ + if (*parser) { + php_http_header_parser_dtor(*parser); + efree(*parser); + *parser = NULL; + } +} + +STATUS php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg) +{ + TSRMLS_FETCH_FROM_CTX(parser->ts); + + while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_is(parser)].need_data) { +#if 0 + const char *state[] = {"START", "KEY", "VALUE", "HEADER_DONE", "DONE"}; + fprintf(stderr, "#HP: %s (avail:%zu, num:%d)\n", php_http_header_parser_state_is(parser) < 0 ? "FAILURE" : state[php_http_header_parser_state_is(parser)], buffer->used, headers?zend_hash_num_elements(headers):0); + _dpf(0, buffer->data, buffer->used); +#endif + switch (php_http_header_parser_state_pop(parser)) { + case PHP_HTTP_HEADER_PARSER_STATE_FAILURE: + return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); + + case PHP_HTTP_HEADER_PARSER_STATE_START: { + char *ptr = buffer->data; + + while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) { + ++ptr; + } + + php_http_buffer_cut(buffer, 0, ptr - buffer->data); + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY); + break; + } + + case PHP_HTTP_HEADER_PARSER_STATE_KEY: { + const char *colon, *eol_str = NULL; + int eol_len = 0; + + if (buffer->data == (eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) { + /* end of headers */ + php_http_buffer_cut(buffer, 0, eol_len); + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_DONE); + } else if (php_http_info_parse(&parser->info, php_http_buffer_fix(buffer)->data TSRMLS_CC)) { + /* new message starting with request/response line */ + if (callback_func) { + callback_func(callback_arg, &headers, &parser->info TSRMLS_CC); + } + php_http_info_dtor(&parser->info); + php_http_buffer_cut(buffer, 0, eol_str + eol_len - buffer->data); + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + } else if ((colon = memchr(buffer->data, ':', buffer->used)) && (!eol_str || eol_str > colon)) { + /* header: string */ + parser->_key.str = estrndup(buffer->data, parser->_key.len = colon - buffer->data); + while (PHP_HTTP_IS_CTYPE(space, *++colon) && *colon != '\n' && *colon != '\r'); + php_http_buffer_cut(buffer, 0, colon - buffer->data); + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); + } else { + /* neither reqeust/response line nor header: string */ + return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE); + } + break; + } + + case PHP_HTTP_HEADER_PARSER_STATE_VALUE: { + const char *eol_str; + int eol_len; + +#define SET_ADD_VAL(slen, eol_len) \ + do { \ + const char *ptr = buffer->data; \ + size_t len = slen; \ + \ + while (len > 0 && PHP_HTTP_IS_CTYPE(space, *ptr)) { \ + ++ptr; \ + --len; \ + } \ + while (len > 0 && PHP_HTTP_IS_CTYPE(space, ptr[len - 1])) { \ + --len; \ + } \ + \ + if (len > 0) { \ + if (parser->_val.str) { \ + parser->_val.str = erealloc(parser->_val.str, parser->_val.len + len + 2); \ + parser->_val.str[parser->_val.len++] = ' '; \ + memcpy(&parser->_val.str[parser->_val.len], ptr, len); \ + parser->_val.len += len; \ + parser->_val.str[parser->_val.len] = '\0'; \ + } else { \ + parser->_val.len = len; \ + parser->_val.str = estrndup(ptr, len); \ + } \ + } \ + php_http_buffer_cut(buffer, 0, slen + eol_len); \ + } while (0) + + if ((eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) { + SET_ADD_VAL(eol_str - buffer->data, eol_len); + + if (buffer->used) { + if (*buffer->data != '\t' && *buffer->data != ' ') { + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + break; + } else { + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); + break; + } + } + } + + if (flags & PHP_HTTP_HEADER_PARSER_CLEANUP) { + if (buffer->used) { + SET_ADD_VAL(buffer->used, 0); + } + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + } else { + return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX); + } + break; + } + + case PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX: + if (*buffer->data == ' ' || *buffer->data == '\t') { + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE); + } else { + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE); + } + break; + + case PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE: + if (parser->_key.str && parser->_val.str) { + zval array, **exist; + + if (!headers && callback_func) { + callback_func(callback_arg, &headers, NULL TSRMLS_CC); + } + + INIT_PZVAL_ARRAY(&array, headers); + php_http_pretty_key(parser->_key.str, parser->_key.len, 1, 1); + if (SUCCESS == zend_symtable_find(headers, parser->_key.str, parser->_key.len + 1, (void *) &exist)) { + convert_to_array(*exist); + add_next_index_stringl(*exist, parser->_val.str, parser->_val.len, 0); + } else { + add_assoc_stringl_ex(&array, parser->_key.str, parser->_key.len + 1, parser->_val.str, parser->_val.len, 0); + } + parser->_val.str = NULL; + } + + STR_SET(parser->_key.str, NULL); + STR_SET(parser->_val.str, NULL); + + php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY); + break; + + case PHP_HTTP_HEADER_PARSER_STATE_DONE: + return PHP_HTTP_HEADER_PARSER_STATE_DONE; + } + } + + return php_http_header_parser_state_is(parser); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_header_parser.h b/php_http_header_parser.h new file mode 100644 index 0000000..1c07da2 --- /dev/null +++ b/php_http_header_parser.h @@ -0,0 +1,64 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_HEADER_PARSER_H +#define PHP_HTTP_HEADER_PARSER_H + +#include "php_http_info.h" + +typedef enum php_http_header_parser_state { + PHP_HTTP_HEADER_PARSER_STATE_FAILURE = FAILURE, + PHP_HTTP_HEADER_PARSER_STATE_START = 0, + PHP_HTTP_HEADER_PARSER_STATE_KEY, + PHP_HTTP_HEADER_PARSER_STATE_VALUE, + PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX, + PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE, + PHP_HTTP_HEADER_PARSER_STATE_DONE +} php_http_header_parser_state_t; + +#define PHP_HTTP_HEADER_PARSER_CLEANUP 0x1 + +typedef struct php_http_header_parser { + zend_stack stack; + php_http_info_t info; + struct { + char *str; + size_t len; + } _key; + struct { + char *str; + size_t len; + } _val; +#ifdef ZTS + void ***ts; +#endif +} php_http_header_parser_t; + +PHP_HTTP_API php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser TSRMLS_DC); +PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...); +PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser); +PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser); +PHP_HTTP_API void php_http_header_parser_dtor(php_http_header_parser_t *parser); +PHP_HTTP_API void php_http_header_parser_free(php_http_header_parser_t **parser); +PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg); + +#endif /* PHP_HTTP_HEADER_PARSER_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_headers_api.h b/php_http_headers_api.h deleted file mode 100644 index 7f22e2a..0000000 --- a/php_http_headers_api.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_HEADERS_API_H -#define PHP_HTTP_HEADERS_API_H - -#include "php_http_info_api.h" - -typedef enum http_range_status_t { - RANGE_OK, - RANGE_NO, - RANGE_ERR -} http_range_status; - -#define http_parse_headers(h, a) _http_parse_headers_ex((h), Z_ARRVAL_P(a), 1, http_info_default_callback, NULL TSRMLS_CC) -#define http_parse_headers_ex(h, ht, p) _http_parse_headers_ex((h), (ht), (p), http_info_default_callback, NULL TSRMLS_CC) -#define http_parse_headers_cb(h, ht, p, f, d) _http_parse_headers_ex((h), (ht), (p), (f), (d) TSRMLS_CC) -PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, http_info_callback callback_func, void **callback_data TSRMLS_DC); - -typedef char *(*negotiate_func_t)(const char *test, double *quality, HashTable *supported TSRMLS_DC); - -#define http_negotiate_language_func _http_negotiate_language_func -extern char *_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC); -#define http_negotiate_content_type_func _http_negotiate_default_func -#define http_negotiate_encoding_func _http_negotiate_default_func -#define http_negotiate_charset_func _http_negotiate_default_func -#define http_negotiate_default_func _http_negotiate_default_func -extern char *_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC); - -#define http_negotiate_language(zsupported) http_negotiate_language_ex(Z_ARRVAL_P(zsupported)) -#define http_negotiate_language_ex(supported) http_negotiate_q("HTTP_ACCEPT_LANGUAGE", (supported), http_negotiate_language_func) -#define http_negotiate_charset(zsupported) http_negotiate_charset_ex(Z_ARRVAL_P(zsupported)) -#define http_negotiate_charset_ex(supported) http_negotiate_q("HTTP_ACCEPT_CHARSET", (supported), http_negotiate_charset_func) -#define http_negotiate_encoding(zsupported) http_negotiate_encoding_ex(Z_ARRVAL_P(zsupported)) -#define http_negotiate_encoding_ex(supported) http_negotiate_q("HTTP_ACCEPT_ENCODING", (supported), http_negotiate_encoding_func) -#define http_negotiate_content_type(zsupported) http_negotiate_content_type_ex(Z_ARRVAL_P(zsupported)) -#define http_negotiate_content_type_ex(supported) http_negotiate_q("HTTP_ACCEPT", (supported), http_negotiate_content_type_func) -#define http_negotiate_q(e, s, n) _http_negotiate_q((e), (s), (n) TSRMLS_CC) -PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *supported, negotiate_func_t neg TSRMLS_DC); -#define http_negotiate_z(z, s, n) _http_negotiate_z((z), (s), (n) TSRMLS_CC) -PHP_HTTP_API HashTable *_http_negotiate_z(zval *value, HashTable *supported, negotiate_func_t neg TSRMLS_DC); - -#define http_get_request_ranges(r, l) _http_get_request_ranges((r), (l) TSRMLS_CC) -PHP_HTTP_API http_range_status _http_get_request_ranges(HashTable *ranges, size_t length TSRMLS_DC); - -#define http_get_request_headers(h) _http_get_request_headers((h) TSRMLS_CC) -PHP_HTTP_API void _http_get_request_headers(HashTable *headers TSRMLS_DC); - -#define http_get_response_headers(h) _http_get_response_headers((h) TSRMLS_CC) -PHP_HTTP_API STATUS _http_get_response_headers(HashTable *headers_ht TSRMLS_DC); - -#define http_match_request_header(h, v) http_match_request_header_ex((h), (v), 0) -#define http_match_request_header_ex(h, v, c) _http_match_request_header_ex((h), (v), (c) TSRMLS_CC) -PHP_HTTP_API zend_bool _http_match_request_header_ex(const char *header, const char *value, zend_bool match_case TSRMLS_DC); - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_inflatestream_object.h b/php_http_inflatestream_object.h deleted file mode 100644 index 590e0fb..0000000 --- a/php_http_inflatestream_object.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_INFLATESTREAM_OBJECT_H -#define PHP_HTTP_INFLATESTREAM_OBJECT_H -#ifdef HTTP_HAVE_ZLIB -#ifdef ZEND_ENGINE_2 - -typedef struct _http_inflatestream_object_t { - zend_object zo; - http_encoding_stream *stream; -} http_inflatestream_object; - -extern zend_class_entry *http_inflatestream_object_ce; -extern zend_function_entry http_inflatestream_object_fe[]; - -extern PHP_MINIT_FUNCTION(http_inflatestream_object); - -#define http_inflatestream_object_new(ce) _http_inflatestream_object_new((ce) TSRMLS_CC) -extern zend_object_value _http_inflatestream_object_new(zend_class_entry *ce TSRMLS_DC); -#define http_inflatestream_object_new_ex(ce, s, ptr) _http_inflatestream_object_new_ex((ce), (s), (ptr) TSRMLS_CC) -extern zend_object_value _http_inflatestream_object_new_ex(zend_class_entry *ce, http_encoding_stream *s, http_inflatestream_object **ptr TSRMLS_DC); -#define http_inflatestream_object_clone(zobj) _http_inflatestream_object_clone_obj(zobj TSRMLS_CC) -extern zend_object_value _http_inflatestream_object_clone_obj(zval *object TSRMLS_DC); -#define http_inflatestream_object_free(o) _http_inflatestream_object_free((o) TSRMLS_CC) -extern void _http_inflatestream_object_free(zend_object *object TSRMLS_DC); - -PHP_METHOD(HttpInflateStream, __construct); -PHP_METHOD(HttpInflateStream, factory); -PHP_METHOD(HttpInflateStream, update); -PHP_METHOD(HttpInflateStream, flush); -PHP_METHOD(HttpInflateStream, finish); - -#endif -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_info.c b/php_http_info.c new file mode 100644 index 0000000..dca784f --- /dev/null +++ b/php_http_info.c @@ -0,0 +1,153 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +php_http_info_t *php_http_info_init(php_http_info_t *i TSRMLS_DC) +{ + if (!i) { + i = emalloc(sizeof(*i)); + } + + memset(i, 0, sizeof(*i)); + + return i; +} + +void php_http_info_dtor(php_http_info_t *i) +{ + switch (i->type) { + case PHP_HTTP_REQUEST: + STR_SET(PHP_HTTP_INFO(i).request.method, NULL); + STR_SET(PHP_HTTP_INFO(i).request.url, NULL); + break; + + case PHP_HTTP_RESPONSE: + STR_SET(PHP_HTTP_INFO(i).response.status, NULL); + break; + + default: + break; + } +} + +void php_http_info_free(php_http_info_t **i) +{ + if (*i) { + php_http_info_dtor(*i); + efree(*i); + *i = NULL; + } +} + +php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header TSRMLS_DC) +{ + const char *end, *http; + zend_bool free_info = !info; + + /* sane parameter */ + if ((!pre_header) || (!*pre_header)) { + return NULL; + } + + /* where's the end of the line */ + if (!(end = php_http_locate_eol(pre_header, NULL))) { + end = pre_header + strlen(pre_header); + } + + /* there must be HTTP/1.x in the line */ + if (!(http = php_http_locate_str(pre_header, end - pre_header, "HTTP/1.", lenof("HTTP/1.")))) { + return NULL; + } + + info = php_http_info_init(info TSRMLS_CC); + + /* and nothing than SPACE or NUL after HTTP/1.x */ + if (!php_http_version_parse(&info->http.version, http TSRMLS_CC) + || (http[lenof("HTTP/1.1")] && (!PHP_HTTP_IS_CTYPE(space, http[lenof("HTTP/1.1")])))) { + if (free_info) { + php_http_info_free(&info); + } + return NULL; + } + +#if 0 + { + char *line = estrndup(pre_header, end - pre_header); + fprintf(stderr, "http_parse_info('%s')\n", line); + efree(line); + } +#endif + + /* is response */ + if (pre_header == http) { + char *status = NULL; + const char *code = http + sizeof("HTTP/1.1"); + + info->type = PHP_HTTP_RESPONSE; + while (' ' == *code) ++code; + if (code && end > code) { + PHP_HTTP_INFO(info).response.code = strtol(code, &status, 10); + } else { + PHP_HTTP_INFO(info).response.code = 0; + } + if (status && end > status) { + while (' ' == *status) ++status; + PHP_HTTP_INFO(info).response.status = estrndup(status, end - status); + } else { + PHP_HTTP_INFO(info).response.status = NULL; + } + + return info; + } + + /* is request */ + else if (*(http - 1) == ' ' && (!http[lenof("HTTP/1.x")] || http[lenof("HTTP/1.x")] == '\r' || http[lenof("HTTP/1.x")] == '\n')) { + const char *url = strchr(pre_header, ' '); + + info->type = PHP_HTTP_REQUEST; + if (url && http > url) { + PHP_HTTP_INFO(info).request.method = estrndup(pre_header, url - pre_header); + while (' ' == *url) ++url; + while (' ' == *(http-1)) --http; + if (http > url) { + PHP_HTTP_INFO(info).request.url = estrndup(url, http - url); + } else { + STR_SET(PHP_HTTP_INFO(info).request.method, NULL); + return NULL; + } + } else { + PHP_HTTP_INFO(info).request.method = NULL; + PHP_HTTP_INFO(info).request.url = NULL; + } + + return info; + } + + /* some darn header containing HTTP/1.x */ + else { + if (free_info) { + php_http_info_free(&info); + } + return NULL; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_info.h b/php_http_info.h new file mode 100644 index 0000000..87aa791 --- /dev/null +++ b/php_http_info.h @@ -0,0 +1,73 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_INFO_H +#define PHP_HTTP_INFO_H + +#include "php_http_version.h" + +#define PHP_HTTP_INFO_REQUEST_FMT_ARGS(_http_ptr, eol) "%s %s HTTP/%u.%u" eol, \ + (_http_ptr)->info.request.method?(_http_ptr)->info.request.method:"UNKNOWN", \ + (_http_ptr)->info.request.url?(_http_ptr)->info.request.url:"/", \ + (_http_ptr)->version.major||(_http_ptr)->version.major?(_http_ptr)->version.major:1, \ + (_http_ptr)->version.major||(_http_ptr)->version.minor?(_http_ptr)->version.minor:1 + +#define PHP_HTTP_INFO_RESPONSE_FMT_ARGS(_http_ptr, eol) "HTTP/%u.%u %d%s%s" eol, \ + (_http_ptr)->version.major||(_http_ptr)->version.major?(_http_ptr)->version.major:1, \ + (_http_ptr)->version.major||(_http_ptr)->version.minor?(_http_ptr)->version.minor:1, \ + (_http_ptr)->info.response.code?(_http_ptr)->info.response.code:200, \ + (_http_ptr)->info.response.status&&*(_http_ptr)->info.response.status ? " ":"", \ + STR_PTR((_http_ptr)->info.response.status) + +typedef struct php_http_info_data { + union { + /* GET /foo/bar */ + struct { char *method; char *url; } request; + /* 200 Ok */ + struct { unsigned code; char *status; } response; + } info; + php_http_version_t version; +} php_http_info_data_t; + +typedef enum php_http_info_type { + PHP_HTTP_NONE = 0, + PHP_HTTP_REQUEST, + PHP_HTTP_RESPONSE +} php_http_info_type_t; + +#define PHP_HTTP_INFO(ptr) (ptr)->http.info +#define PHP_HTTP_INFO_IMPL(_http, _type) \ + php_http_info_data_t _http; \ + php_http_info_type_t _type; + +typedef struct php_http_info { + PHP_HTTP_INFO_IMPL(http, type) +} php_http_info_t; + +typedef zend_bool (*php_http_info_callback_t)(void **callback_data, HashTable **headers, php_http_info_t *info TSRMLS_DC); + +PHP_HTTP_API php_http_info_t *php_http_info_init(php_http_info_t *info TSRMLS_DC); +PHP_HTTP_API php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header TSRMLS_DC); +PHP_HTTP_API void php_http_info_dtor(php_http_info_t *info); +PHP_HTTP_API void php_http_info_free(php_http_info_t **info); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_info_api.h b/php_http_info_api.h deleted file mode 100644 index a6c2fe8..0000000 --- a/php_http_info_api.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_INFO_API_H -#define PHP_HTTP_INFO_API_H - -#define IS_HTTP_REQUEST 1 -#define IS_HTTP_RESPONSE 2 - -#define HTTP_INFO(ptr) (ptr)->http.info - -#define HTTP_INFO_REQUEST_FMT_ARGS(_http_ptr, _EOL) "%s %s HTTP/%1.1f" _EOL, \ - (_http_ptr)->info.request.method?(_http_ptr)->info.request.method:"UNKNOWN", \ - (_http_ptr)->info.request.url?(_http_ptr)->info.request.url:"/", \ - (_http_ptr)->version>0.0?(_http_ptr)->version:1.1 - -#define HTTP_INFO_RESPONSE_FMT_ARGS(_http_ptr, _EOL) "HTTP/%1.1f %d%s%s" _EOL, \ - (_http_ptr)->version>0.0?(_http_ptr)->version:1.1, \ - (_http_ptr)->info.response.code?(_http_ptr)->info.response.code:200, \ - (_http_ptr)->info.response.status&&*(_http_ptr)->info.response.status ? " ":"", \ - STR_PTR((_http_ptr)->info.response.status) - -typedef struct _http_request_info_t { - char *method; - char *url; -} http_request_info; - -typedef struct _http_response_info_t { - int code; - char *status; -} http_response_info; - -typedef union _http_info_union_t { - http_request_info request; - http_response_info response; -} http_info_union; - -struct http_info { - http_info_union info; - double version; -}; - -typedef struct _http_info_t { - struct http_info http; - int type; -} http_info; - -typedef void (*http_info_callback)(void **callback_data, HashTable **headers, http_info *info TSRMLS_DC); - -#define http_info_default_callback _http_info_default_callback -PHP_HTTP_API void _http_info_default_callback(void **nothing, HashTable **headers, http_info *info TSRMLS_DC); -#define http_info_dtor _http_info_dtor -PHP_HTTP_API void _http_info_dtor(http_info *info); -#define http_info_parse(p, i) _http_info_parse_ex((p), (i), 1 TSRMLS_CC) -#define http_info_parse_ex(p, i, s) _http_info_parse_ex((p), (i), (s) TSRMLS_CC) -PHP_HTTP_API STATUS _http_info_parse_ex(const char *pre_header, http_info *info , zend_bool silent TSRMLS_DC); - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_message.c b/php_http_message.c new file mode 100644 index 0000000..f3509a4 --- /dev/null +++ b/php_http_message.c @@ -0,0 +1,2004 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +static void message_headers(php_http_message_t *msg, php_http_buffer_t *str); + +zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info TSRMLS_DC) +{ + php_http_message_t *old = *message; + + /* advance message */ + if (!old || old->type || zend_hash_num_elements(&old->hdrs)) { + (*message) = php_http_message_init(NULL, 0, NULL TSRMLS_CC); + (*message)->parent = old; + if (headers) { + (*headers) = &((*message)->hdrs); + } + } + + if (info) { + php_http_message_set_info(*message, info); + } + + return old != *message; +} + +php_http_message_t *php_http_message_init(php_http_message_t *message, php_http_message_type_t type, php_http_message_body_t *body TSRMLS_DC) +{ + if (!message) { + message = emalloc(sizeof(*message)); + } + memset(message, 0, sizeof(*message)); + TSRMLS_SET_CTX(message->ts); + + php_http_message_set_type(message, type); + message->http.version.major = 1; + message->http.version.minor = 1; + zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0); + message->body = body ? body : php_http_message_body_init(NULL, NULL TSRMLS_CC); + + return message; +} + +php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_http_message_type_t type TSRMLS_DC) +{ + int free_msg = !message; + zval *sval, tval; + php_http_message_body_t *mbody; + + switch (type) { + case PHP_HTTP_REQUEST: + mbody = php_http_env_get_request_body(TSRMLS_C); + php_http_message_body_addref(mbody); + message = php_http_message_init(message, type, mbody TSRMLS_CC); + if ((sval = php_http_env_get_server_var(ZEND_STRL("SERVER_PROTOCOL"), 1 TSRMLS_CC)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) { + php_http_version_parse(&message->http.version, Z_STRVAL_P(sval) TSRMLS_CC); + } + if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_METHOD"), 1 TSRMLS_CC))) { + message->http.info.request.method = estrdup(Z_STRVAL_P(sval)); + } + if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1 TSRMLS_CC))) { + message->http.info.request.url = estrdup(Z_STRVAL_P(sval)); + } + + php_http_env_get_request_headers(&message->hdrs TSRMLS_CC); + break; + + case PHP_HTTP_RESPONSE: + message = php_http_message_init(NULL, type, NULL TSRMLS_CC); + if (!SG(sapi_headers).http_status_line || !php_http_info_parse((php_http_info_t *) &message->http, SG(sapi_headers).http_status_line TSRMLS_CC)) { + if (!(message->http.info.response.code = SG(sapi_headers).http_response_code)) { + message->http.info.response.code = 200; + } + message->http.info.response.status = estrdup(php_http_env_get_response_status_for_code(message->http.info.response.code)); + } + + php_http_env_get_response_headers(&message->hdrs TSRMLS_CC); +#if PHP_VERSION_ID >= 50400 + if (php_output_get_level(TSRMLS_C)) { + if (php_output_get_status(TSRMLS_C) & PHP_OUTPUT_SENT) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch response body, output has already been sent at %s:%d", php_output_get_start_filename(TSRMLS_C), php_output_get_start_lineno(TSRMLS_C)); + goto error; + } else if (SUCCESS != php_output_get_contents(&tval TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch response body"); + goto error; + } else { + php_http_message_body_append(message->body, Z_STRVAL(tval), Z_STRLEN(tval)); + zval_dtor(&tval); + } + } +#endif + break; + + default: + error: + if (free_msg) { + if (message) { + php_http_message_free(&message); + } + } else { + message = NULL; + } + break; + } + + return message; +} + +php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy TSRMLS_DC) +{ + php_http_message_parser_t p; + php_http_buffer_t buf; + unsigned flags = PHP_HTTP_MESSAGE_PARSER_CLEANUP; + int free_msg; + + php_http_buffer_from_string_ex(&buf, str, len); + php_http_message_parser_init(&p TSRMLS_CC); + + if ((free_msg = !msg)) { + msg = php_http_message_init(NULL, 0, NULL TSRMLS_CC); + } + + if (greedy) { + flags |= PHP_HTTP_MESSAGE_PARSER_GREEDY; + } + if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(&p, &buf, flags, &msg)) { + if (free_msg) { + php_http_message_free(&msg); + } + msg = NULL; + } + + php_http_message_parser_dtor(&p); + php_http_buffer_dtor(&buf); + + return msg; +} + +zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len, int join) +{ + zval *ret = NULL, **header; + char *key = php_http_pretty_key(estrndup(key_str, key_len), key_len, 1, 1); + + if (SUCCESS == zend_symtable_find(&msg->hdrs, key, key_len + 1, (void *) &header)) { + if (join && Z_TYPE_PP(header) == IS_ARRAY) { + TSRMLS_FETCH_FROM_CTX(msg->ts); + + ret = php_http_header_value_to_string(*header TSRMLS_CC); + } else { + Z_ADDREF_PP(header); + ret = *header; + } + } + + efree(key); + + return ret; +} + +zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary) +{ + zval *ct = php_http_message_header(msg, ZEND_STRL("Content-Type"), 1); + zend_bool is_multipart = 0; + TSRMLS_FETCH_FROM_CTX(msg->ts); + + if (ct) { + php_http_params_opts_t popts; + HashTable params; + + ZEND_INIT_SYMTABLE(¶ms); + php_http_params_opts_default_get(&popts); + popts.input.str = Z_STRVAL_P(ct); + popts.input.len = Z_STRLEN_P(ct); + + if (php_http_params_parse(¶ms, &popts TSRMLS_CC)) { + zval **cur, **arg; + char *ct_str; + + zend_hash_internal_pointer_reset(¶ms); + + if (SUCCESS == zend_hash_get_current_data(¶ms, (void *) &cur) + && Z_TYPE_PP(cur) == IS_ARRAY + && HASH_KEY_IS_STRING == zend_hash_get_current_key(¶ms, &ct_str, NULL, 0) + ) { + if (php_http_match(ct_str, "multipart", PHP_HTTP_MATCH_WORD)) { + is_multipart = 1; + + /* get boundary */ + if (boundary + && SUCCESS == zend_hash_find(Z_ARRVAL_PP(cur), ZEND_STRS("arguments"), (void *) &arg) + && Z_TYPE_PP(arg) == IS_ARRAY + ) { + zval **val; + HashPosition pos; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + + FOREACH_KEYVAL(pos, *arg, key, val) { + if (key.type == HASH_KEY_IS_STRING && !strcasecmp(key.str, "boundary")) { + zval *bnd = php_http_ztyp(IS_STRING, *val); + + if (Z_STRLEN_P(bnd)) { + *boundary = estrndup(Z_STRVAL_P(bnd), Z_STRLEN_P(bnd)); + } + zval_ptr_dtor(&bnd); + } + } + } + } + } + } + zend_hash_destroy(¶ms); + zval_ptr_dtor(&ct); + } + + return is_multipart; +} + +/* */ +void php_http_message_set_type(php_http_message_t *message, php_http_message_type_t type) +{ + /* just act if different */ + if (type != message->type) { + + /* free request info */ + switch (message->type) { + case PHP_HTTP_REQUEST: + STR_FREE(message->http.info.request.method); + STR_FREE(message->http.info.request.url); + break; + + case PHP_HTTP_RESPONSE: + STR_FREE(message->http.info.response.status); + break; + + default: + break; + } + + message->type = type; + memset(&message->http, 0, sizeof(message->http)); + } +} + +void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info) +{ + php_http_message_set_type(message, info->type); + message->http.version = info->http.version; + switch (message->type) { + case PHP_HTTP_REQUEST: + STR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? estrdup(PHP_HTTP_INFO(info).request.url) : NULL); + STR_SET(PHP_HTTP_INFO(message).request.method, PHP_HTTP_INFO(info).request.method ? estrdup(PHP_HTTP_INFO(info).request.method) : NULL); + break; + + case PHP_HTTP_RESPONSE: + PHP_HTTP_INFO(message).response.code = PHP_HTTP_INFO(info).response.code; + STR_SET(PHP_HTTP_INFO(message).response.status, PHP_HTTP_INFO(info).response.status ? estrdup(PHP_HTTP_INFO(info).response.status) : NULL); + break; + + default: + break; + } +} + +void php_http_message_update_headers(php_http_message_t *msg) +{ + zval *h; + size_t size; + + if (php_http_message_body_stream(msg->body)->readfilters.head) { + /* if a read stream filter is attached to the body the caller must also care for the headers */ + } else if ((size = php_http_message_body_size(msg->body))) { + MAKE_STD_ZVAL(h); + ZVAL_LONG(h, size); + zend_hash_update(&msg->hdrs, "Content-Length", sizeof("Content-Length"), &h, sizeof(zval *), NULL); + + if (msg->body->boundary) { + char *str; + size_t len; + + if (!(h = php_http_message_header(msg, ZEND_STRL("Content-Type"), 1))) { + len = spprintf(&str, 0, "multipart/form-data; boundary=\"%s\"", msg->body->boundary); + MAKE_STD_ZVAL(h); + ZVAL_STRINGL(h, str, len, 0); + zend_hash_update(&msg->hdrs, "Content-Type", sizeof("Content-Type"), &h, sizeof(zval *), NULL); + } else if (!php_http_match(Z_STRVAL_P(h), "boundary=", PHP_HTTP_MATCH_WORD)) { + zval_dtor(h); + Z_STRLEN_P(h) = spprintf(&Z_STRVAL_P(h), 0, "%s; boundary=\"%s\"", Z_STRVAL_P(h), msg->body->boundary); + zend_hash_update(&msg->hdrs, "Content-Type", sizeof("Content-Type"), &h, sizeof(zval *), NULL); + } else { + zval_ptr_dtor(&h); + } + } + } +} + +static void message_headers(php_http_message_t *msg, php_http_buffer_t *str) +{ + TSRMLS_FETCH_FROM_CTX(msg->ts); + + switch (msg->type) { + case PHP_HTTP_REQUEST: + php_http_buffer_appendf(str, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, PHP_HTTP_CRLF)); + break; + + case PHP_HTTP_RESPONSE: + php_http_buffer_appendf(str, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, PHP_HTTP_CRLF)); + break; + + default: + break; + } + + php_http_message_update_headers(msg); + php_http_header_to_string(str, &msg->hdrs TSRMLS_CC); +} + +void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg) +{ + php_http_buffer_t str; + + php_http_buffer_init_ex(&str, 0x1000, 0); + message_headers(msg, &str); + cb(cb_arg, str.data, str.used); + php_http_buffer_dtor(&str); + + if (php_http_message_body_size(msg->body)) { + cb(cb_arg, ZEND_STRL(PHP_HTTP_CRLF)); + php_http_message_body_to_callback(msg->body, cb, cb_arg, 0, 0); + } +} + +void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length) +{ + php_http_buffer_t str; + char *data; + + php_http_buffer_init_ex(&str, 0x1000, 0); + message_headers(msg, &str); + if (php_http_message_body_size(msg->body)) { + php_http_buffer_appends(&str, PHP_HTTP_CRLF); + php_http_message_body_to_callback(msg->body, (php_http_pass_callback_t) php_http_buffer_append, &str, 0, 0); + } + + data = php_http_buffer_data(&str, string, length); + if (!string) { + efree(data); + } + + php_http_buffer_dtor(&str); +} + +void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length) +{ + char *buf; + php_http_buffer_t str; + php_http_message_t *msg; + + php_http_buffer_init(&str); + + msg = message = php_http_message_reverse(message); + do { + php_http_message_to_callback(message, (php_http_pass_callback_t) php_http_buffer_append, &str); + php_http_buffer_appends(&str, PHP_HTTP_CRLF); + } while ((message = message->parent)); + php_http_message_reverse(msg); + + buf = php_http_buffer_data(&str, string, length); + if (!string) { + efree(buf); + } + + php_http_buffer_dtor(&str); +} + +php_http_message_t *php_http_message_reverse(php_http_message_t *msg) +{ + int i, c = 0; + + php_http_message_count(c, msg); + + if (c > 1) { + php_http_message_t *tmp = msg, **arr; + + arr = ecalloc(c, sizeof(**arr)); + for (i = 0; i < c; ++i) { + arr[i] = tmp; + tmp = tmp->parent; + } + arr[0]->parent = NULL; + for (i = 0; i < c-1; ++i) { + arr[i+1]->parent = arr[i]; + } + + msg = arr[c-1]; + efree(arr); + } + + return msg; +} + +php_http_message_t *php_http_message_zip(php_http_message_t *one, php_http_message_t *two) +{ + php_http_message_t *dst = php_http_message_copy(one, NULL), *src = php_http_message_copy(two, NULL), *tmp_dst, *tmp_src, *ret = dst; + + while(dst && src) { + tmp_dst = dst->parent; + tmp_src = src->parent; + dst->parent = src; + if (tmp_dst) { + src->parent = tmp_dst; + } + src = tmp_src; + dst = tmp_dst; + } + + return ret; +} + +php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents) +{ + php_http_message_t *temp, *copy = NULL; + php_http_info_t info; + TSRMLS_FETCH_FROM_CTX(from->ts); + + if (from) { + info.type = from->type; + info.http = from->http; + + copy = temp = php_http_message_init(to, 0, php_http_message_body_copy(from->body, NULL) TSRMLS_CC); + php_http_message_set_info(temp, &info); + zend_hash_copy(&temp->hdrs, &from->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + + if (parents) while (from->parent) { + info.type = from->parent->type; + info.http = from->parent->http; + + temp->parent = php_http_message_init(NULL, 0, php_http_message_body_copy(from->parent->body, NULL) TSRMLS_CC); + php_http_message_set_info(temp->parent, &info); + zend_hash_copy(&temp->parent->hdrs, &from->parent->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + + temp = temp->parent; + from = from->parent; + } + } + + return copy; +} + +php_http_message_t *php_http_message_copy(php_http_message_t *from, php_http_message_t *to) +{ + return php_http_message_copy_ex(from, to, 1); +} + +void php_http_message_dtor(php_http_message_t *message) +{ + if (message) { + zend_hash_destroy(&message->hdrs); + php_http_message_body_free(&message->body); + + switch (message->type) { + case PHP_HTTP_REQUEST: + STR_SET(message->http.info.request.method, NULL); + STR_SET(message->http.info.request.url, NULL); + break; + + case PHP_HTTP_RESPONSE: + STR_SET(message->http.info.response.status, NULL); + break; + + default: + break; + } + } +} + +void php_http_message_free(php_http_message_t **message) +{ + if (*message) { + if ((*message)->parent) { + php_http_message_free(&(*message)->parent); + } + php_http_message_dtor(*message); + efree(*message); + *message = NULL; + } +} + +static zval *php_http_message_object_read_prop(zval *object, zval *member, int type PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC); +static void php_http_message_object_write_prop(zval *object, zval *member, zval *value PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC); +static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC); + +static zend_object_handlers php_http_message_object_handlers; +static HashTable php_http_message_object_prophandlers; + +typedef void (*php_http_message_object_prophandler_func_t)(php_http_message_object_t *o, zval *v TSRMLS_DC); + +typedef struct php_http_message_object_prophandler { + php_http_message_object_prophandler_func_t read; + php_http_message_object_prophandler_func_t write; +} php_http_message_object_prophandler_t; + +static STATUS php_http_message_object_add_prophandler(const char *prop_str, size_t prop_len, php_http_message_object_prophandler_func_t read, php_http_message_object_prophandler_func_t write) { + php_http_message_object_prophandler_t h = { read, write }; + return zend_hash_add(&php_http_message_object_prophandlers, prop_str, prop_len + 1, (void *) &h, sizeof(h), NULL); +} +static STATUS php_http_message_object_get_prophandler(const char *prop_str, size_t prop_len, php_http_message_object_prophandler_t **handler) { + return zend_hash_find(&php_http_message_object_prophandlers, prop_str, prop_len + 1, (void *) handler); +} +static void php_http_message_object_prophandler_get_type(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { + RETVAL_LONG(obj->message->type); +} +static void php_http_message_object_prophandler_set_type(php_http_message_object_t *obj, zval *value TSRMLS_DC) { + zval *cpy = php_http_ztyp(IS_LONG, value); + php_http_message_set_type(obj->message, Z_LVAL_P(cpy)); + zval_ptr_dtor(&cpy); +} +static void php_http_message_object_prophandler_get_request_method(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { + if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) { + RETVAL_STRING(obj->message->http.info.request.method, 1); + } else { + RETVAL_NULL(); + } +} +static void php_http_message_object_prophandler_set_request_method(php_http_message_object_t *obj, zval *value TSRMLS_DC) { + if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) { + zval *cpy = php_http_ztyp(IS_STRING, value); + STR_SET(obj->message->http.info.request.method, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy))); + zval_ptr_dtor(&cpy); + } +} +static void php_http_message_object_prophandler_get_request_url(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { + if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url) { + RETVAL_STRING(obj->message->http.info.request.url, 1); + } else { + RETVAL_NULL(); + } +} +static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value TSRMLS_DC) { + if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) { + zval *cpy = php_http_ztyp(IS_STRING, value); + STR_SET(obj->message->http.info.request.url, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy))); + zval_ptr_dtor(&cpy); + } +} +static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { + if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) { + RETVAL_STRING(obj->message->http.info.response.status, 1); + } else { + RETVAL_NULL(); + } +} +static void php_http_message_object_prophandler_set_response_status(php_http_message_object_t *obj, zval *value TSRMLS_DC) { + if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) { + zval *cpy = php_http_ztyp(IS_STRING, value); + STR_SET(obj->message->http.info.response.status, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy))); + zval_ptr_dtor(&cpy); + } +} +static void php_http_message_object_prophandler_get_response_code(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { + if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) { + RETVAL_LONG(obj->message->http.info.response.code); + } else { + RETVAL_NULL(); + } +} +static void php_http_message_object_prophandler_set_response_code(php_http_message_object_t *obj, zval *value TSRMLS_DC) { + if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) { + zval *cpy = php_http_ztyp(IS_LONG, value); + obj->message->http.info.response.code = Z_LVAL_P(cpy); + STR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(obj->message->http.info.response.code))); + zval_ptr_dtor(&cpy); + } +} +static void php_http_message_object_prophandler_get_http_version(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { + char *version_str; + size_t version_len; + + php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL TSRMLS_CC); + RETVAL_STRINGL(version_str, version_len, 0); +} +static void php_http_message_object_prophandler_set_http_version(php_http_message_object_t *obj, zval *value TSRMLS_DC) { + zval *cpy = php_http_ztyp(IS_STRING, value); + php_http_version_parse(&obj->message->http.version, Z_STRVAL_P(cpy) TSRMLS_CC); + zval_ptr_dtor(&cpy); +} +static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { + array_init(return_value); + zend_hash_copy(Z_ARRVAL_P(return_value), &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); +} +static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value TSRMLS_DC) { + zval *cpy = php_http_ztyp(IS_ARRAY, value); + + zend_hash_clean(&obj->message->hdrs); + zend_hash_copy(&obj->message->hdrs, Z_ARRVAL_P(cpy), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + zval_ptr_dtor(&cpy); +} +static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { + if (obj->body) { + RETVAL_OBJVAL(obj->body->zv, 1); + } else { + RETVAL_NULL(); + } +} +static void php_http_message_object_prophandler_set_body(php_http_message_object_t *obj, zval *value TSRMLS_DC) { + php_http_message_object_set_body(obj, value TSRMLS_CC); +} +static void php_http_message_object_prophandler_get_parent_message(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { + if (obj->message->parent) { + RETVAL_OBJVAL(obj->parent->zv, 1); + } else { + RETVAL_NULL(); + } +} +static void php_http_message_object_prophandler_set_parent_message(php_http_message_object_t *obj, zval *value TSRMLS_DC) { + if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_message_class_entry TSRMLS_CC)) { + php_http_message_object_t *parent_obj = zend_object_store_get_object(value TSRMLS_CC); + + if (obj->message->parent) { + zend_objects_store_del_ref_by_handle(obj->parent->zv.handle TSRMLS_CC); + } + Z_OBJ_ADDREF_P(value); + obj->parent = parent_obj; + obj->message->parent = parent_obj->message; + } +} + +#define PHP_HTTP_MESSAGE_OBJECT_INIT(obj) \ + do { \ + if (!obj->message) { \ + obj->message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); \ + } \ + } while(0) + + +void php_http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC) +{ + int i = 0; + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + /* count */ + php_http_message_count(i, obj->message); + + if (i > 1) { + php_http_message_object_t **objects; + int last; + + objects = ecalloc(i, sizeof(**objects)); + + /* we are the first message */ + objects[0] = obj; + + /* fetch parents */ + for (i = 1; obj->parent; ++i) { + objects[i] = obj = obj->parent; + } + + /* reorder parents */ + for (last = --i; i; --i) { + objects[i]->message->parent = objects[i-1]->message; + objects[i]->parent = objects[i-1]; + } + + objects[0]->message->parent = NULL; + objects[0]->parent = NULL; + + /* add ref, because we previously have not been a parent message */ + Z_OBJ_ADDREF_P(getThis()); + RETVAL_OBJVAL(objects[last]->zv, 0); + + efree(objects); + } else { + RETURN_ZVAL(getThis(), 1, 0); + } +} + +void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top TSRMLS_DC) +{ + zval m; + php_http_message_t *save_parent_msg = NULL; + php_http_message_object_t *save_parent_obj = NULL, *obj = zend_object_store_get_object(this_ptr TSRMLS_CC); + php_http_message_object_t *prepend_obj = zend_object_store_get_object(prepend TSRMLS_CC); + + INIT_PZVAL(&m); + m.type = IS_OBJECT; + + if (!top) { + save_parent_obj = obj->parent; + save_parent_msg = obj->message->parent; + } else { + /* iterate to the most parent object */ + while (obj->parent) { + obj = obj->parent; + } + } + + /* prepend */ + obj->parent = prepend_obj; + obj->message->parent = prepend_obj->message; + + /* add ref */ + zend_objects_store_add_ref(prepend TSRMLS_CC); + + if (!top) { + prepend_obj->parent = save_parent_obj; + prepend_obj->message->parent = save_parent_msg; + } +} + +STATUS php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval *zbody TSRMLS_DC) +{ + zval *tmp = NULL; + php_stream *s; + zend_object_value ov; + php_http_message_body_t *body; + php_http_message_body_object_t *body_obj; + + switch (Z_TYPE_P(zbody)) { + case IS_RESOURCE: + php_stream_from_zval_no_verify(s, &zbody); + if (!s) { + php_http_throw(unexpected_val, "The stream is not a valid resource", NULL); + return FAILURE; + } + + is_resource: + + body = php_http_message_body_init(NULL, s TSRMLS_CC); + if (SUCCESS != php_http_new(&ov, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, body, NULL TSRMLS_CC)) { + php_http_message_body_free(&body); + return FAILURE; + } + MAKE_STD_ZVAL(tmp); + ZVAL_OBJVAL(tmp, ov, 0); + zbody = tmp; + break; + + case IS_OBJECT: + if (instanceof_function(Z_OBJCE_P(zbody), php_http_message_body_class_entry TSRMLS_CC)) { + Z_OBJ_ADDREF_P(zbody); + break; + } + /* no break */ + + default: + tmp = php_http_ztyp(IS_STRING, zbody); + s = php_stream_temp_new(); + php_stream_write(s, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + zval_ptr_dtor(&tmp); + tmp = NULL; + goto is_resource; + + } + + body_obj = zend_object_store_get_object(zbody TSRMLS_CC); + + if (msg_obj->body) { + zend_objects_store_del_ref_by_handle(msg_obj->body->zv.handle TSRMLS_CC); + } + if (msg_obj->message) { + php_http_message_body_free(&msg_obj->message->body); + msg_obj->message->body = php_http_message_body_init(&body_obj->body, NULL TSRMLS_CC); + } else { + msg_obj->message = php_http_message_init(NULL, 0, php_http_message_body_init(&body_obj->body, NULL TSRMLS_CC) TSRMLS_CC); + } + msg_obj->body = body_obj; + + if (tmp) { + FREE_ZVAL(tmp); + } + return SUCCESS; +} + +zend_object_value php_http_message_object_new(zend_class_entry *ce TSRMLS_DC) +{ + return php_http_message_object_new_ex(ce, NULL, NULL TSRMLS_CC); +} + +zend_object_value php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg, php_http_message_object_t **ptr TSRMLS_DC) +{ + php_http_message_object_t *o; + + o = ecalloc(1, sizeof(php_http_message_object_t)); + zend_object_std_init((zend_object *) o, ce TSRMLS_CC); + object_properties_init((zend_object *) o, ce); + + if (ptr) { + *ptr = o; + } + + if (msg) { + o->message = msg; + if (msg->parent) { + php_http_message_object_new_ex(ce, msg->parent, &o->parent TSRMLS_CC); + } + php_http_message_body_object_new_ex(php_http_message_body_class_entry, php_http_message_body_init(&msg->body, NULL TSRMLS_CC), &o->body TSRMLS_CC); + } + + o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_message_object_free, NULL TSRMLS_CC); + o->zv.handlers = &php_http_message_object_handlers; + + return o->zv; +} + +zend_object_value php_http_message_object_clone(zval *this_ptr TSRMLS_DC) +{ + zend_object_value new_ov; + php_http_message_object_t *new_obj = NULL; + php_http_message_object_t *old_obj = zend_object_store_get_object(this_ptr TSRMLS_CC); + + new_ov = php_http_message_object_new_ex(old_obj->zo.ce, php_http_message_copy(old_obj->message, NULL), &new_obj TSRMLS_CC); + zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); + + return new_ov; +} + +void php_http_message_object_free(void *object TSRMLS_DC) +{ + php_http_message_object_t *o = (php_http_message_object_t *) object; + + if (o->iterator) { + zval_ptr_dtor(&o->iterator); + o->iterator = NULL; + } + if (o->message) { + /* do NOT free recursivly */ + php_http_message_dtor(o->message); + efree(o->message); + o->message = NULL; + } + if (o->parent) { + zend_objects_store_del_ref_by_handle(o->parent->zv.handle TSRMLS_CC); + o->parent = NULL; + } + if (o->body) { + zend_objects_store_del_ref_by_handle(o->body->zv.handle TSRMLS_CC); + o->body = NULL; + } + zend_object_std_dtor((zend_object *) o TSRMLS_CC); + efree(o); +} + +static zval *php_http_message_object_read_prop(zval *object, zval *member, int type PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC) +{ + php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); + php_http_message_object_prophandler_t *handler; + zval *return_value, *copy = php_http_ztyp(IS_STRING, member); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (SUCCESS == php_http_message_object_get_prophandler(Z_STRVAL_P(copy), Z_STRLEN_P(copy), &handler)) { + ALLOC_ZVAL(return_value); + Z_SET_REFCOUNT_P(return_value, 0); + Z_UNSET_ISREF_P(return_value); + + if (type == BP_VAR_R) { + handler->read(obj, return_value TSRMLS_CC); + } else { + php_property_proxy_t *proxy = php_property_proxy_init(object, Z_STRVAL_P(copy), Z_STRLEN_P(copy) TSRMLS_CC); + RETVAL_OBJVAL(php_property_proxy_object_new_ex(php_property_proxy_get_class_entry(), proxy, NULL TSRMLS_CC), 0); + } + } else { + return_value = zend_get_std_object_handlers()->read_property(object, member, type PHP_HTTP_ZEND_LITERAL_CC TSRMLS_CC); + } + + zval_ptr_dtor(©); + + return return_value; +} + +static void php_http_message_object_write_prop(zval *object, zval *member, zval *value PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC) +{ + php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); + php_http_message_object_prophandler_t *handler; + zval *copy = php_http_ztyp(IS_STRING, member); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (SUCCESS == php_http_message_object_get_prophandler(Z_STRVAL_P(copy), Z_STRLEN_P(copy), &handler)) { + handler->write(obj, value TSRMLS_CC); + } else { + zend_get_std_object_handlers()->write_property(object, member, value PHP_HTTP_ZEND_LITERAL_CC TSRMLS_CC); + } + + zval_ptr_dtor(©); +} + +static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC) +{ + zval *headers; + php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); + php_http_message_t *msg = obj->message; + HashTable *props = zend_get_std_object_handlers()->get_properties(object TSRMLS_CC); + zval array, *parent, *body; + char *version; + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + INIT_PZVAL_ARRAY(&array, props); + +#define ASSOC_PROP(ptype, n, val) \ + do { \ + zend_property_info *pi; \ + if (SUCCESS == zend_hash_find(&obj->zo.ce->properties_info, n, sizeof(n), (void *) &pi)) { \ + add_assoc_ ##ptype## _ex(&array, pi->name, pi->name_length + 1, val); \ + } \ + } while(0) \ + +#define ASSOC_STRING(name, val) ASSOC_STRINGL(name, val, strlen(val)) +#define ASSOC_STRINGL(name, val, len) ASSOC_STRINGL_EX(name, val, len, 1) +#define ASSOC_STRINGL_EX(n, val, len, cpy) \ + do { \ + zend_property_info *pi; \ + if (SUCCESS == zend_hash_find(&obj->zo.ce->properties_info, n, sizeof(n), (void *) &pi)) { \ + add_assoc_stringl_ex(&array, pi->name, pi->name_length + 1, val, len, cpy); \ + } \ + } while(0) + + ASSOC_PROP(long, "type", msg->type); + ASSOC_STRINGL_EX("httpVersion", version, spprintf(&version, 0, "%u.%u", msg->http.version.major, msg->http.version.minor), 0); + + switch (msg->type) { + case PHP_HTTP_REQUEST: + ASSOC_PROP(long, "responseCode", 0); + ASSOC_STRINGL("responseStatus", "", 0); + ASSOC_STRING("requestMethod", STR_PTR(msg->http.info.request.method)); + ASSOC_STRING("requestUrl", STR_PTR(msg->http.info.request.url)); + break; + + case PHP_HTTP_RESPONSE: + ASSOC_PROP(long, "responseCode", msg->http.info.response.code); + ASSOC_STRING("responseStatus", STR_PTR(msg->http.info.response.status)); + ASSOC_STRINGL("requestMethod", "", 0); + ASSOC_STRINGL("requestUrl", "", 0); + break; + + case PHP_HTTP_NONE: + default: + ASSOC_PROP(long, "responseCode", 0); + ASSOC_STRINGL("responseStatus", "", 0); + ASSOC_STRINGL("requestMethod", "", 0); + ASSOC_STRINGL("requestUrl", "", 0); + break; + } + + MAKE_STD_ZVAL(headers); + array_init(headers); + zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + ASSOC_PROP(zval, "headers", headers); + + MAKE_STD_ZVAL(body); + if (!obj->body) { + php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, (void *) php_http_message_body_init(&obj->message->body, NULL TSRMLS_CC), (void *) &obj->body TSRMLS_CC); + } + ZVAL_OBJVAL(body, obj->body->zv, 1); + ASSOC_PROP(zval, "body", body); + + MAKE_STD_ZVAL(parent); + if (msg->parent) { + ZVAL_OBJVAL(parent, obj->parent->zv, 1); + } else { + ZVAL_NULL(parent); + } + ASSOC_PROP(zval, "parentMessage", parent); + + return props; +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___construct, 0, 0, 0) + ZEND_ARG_INFO(0, message) + ZEND_ARG_INFO(0, greedy) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, __construct) +{ + zend_bool greedy = 1; + zval *zmessage = NULL; + php_http_message_t *msg = NULL; + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zend_error_handling zeh; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!b", &zmessage, &greedy), invalid_arg, return); + + zend_replace_error_handling(EH_THROW, php_http_exception_bad_message_class_entry, &zeh TSRMLS_CC); + if (zmessage && Z_TYPE_P(zmessage) == IS_RESOURCE) { + php_stream *s; + php_http_message_parser_t p; + zend_error_handling zeh; + + zend_replace_error_handling(EH_THROW, php_http_exception_unexpected_val_class_entry, &zeh TSRMLS_CC); + php_stream_from_zval(s, &zmessage); + zend_restore_error_handling(&zeh TSRMLS_CC); + + if (s && php_http_message_parser_init(&p TSRMLS_CC)) { + unsigned flags = (greedy ? PHP_HTTP_MESSAGE_PARSER_GREEDY : 0); + + if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse_stream(&p, s, flags, &msg)) { + if (!EG(exception)) { + php_http_throw(bad_message, "Could not parse message from stream", NULL); + } + } + + php_http_message_parser_dtor(&p); + } + + if (!msg && !EG(exception)) { + php_http_throw(bad_message, "Empty message received from stream", NULL); + } + } else if (zmessage) { + zmessage = php_http_ztyp(IS_STRING, zmessage); + msg = php_http_message_parse(NULL, Z_STRVAL_P(zmessage), Z_STRLEN_P(zmessage), greedy TSRMLS_CC); + + if (!msg && !EG(exception)) { + php_http_throw(bad_message, "Could not parse message: %.*s", MIN(25, Z_STRLEN_P(zmessage)), Z_STRVAL_P(zmessage)); + } + zval_ptr_dtor(&zmessage); + } + + if (msg) { + php_http_message_dtor(obj->message); + obj->message = msg; + if (obj->message->parent) { + php_http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, &obj->parent TSRMLS_CC); + } + } + zend_restore_error_handling(&zeh TSRMLS_CC); + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getBody, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getBody) +{ + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (!obj->body) { + php_http_message_body_addref(obj->message->body); + php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, obj->message->body, (void *) &obj->body TSRMLS_CC); + } + if (obj->body) { + RETVAL_OBJVAL(obj->body->zv, 1); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setBody, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setBody) +{ + zval *zbody; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zbody, php_http_message_body_class_entry)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + php_http_message_object_prophandler_set_body(obj, zbody TSRMLS_CC); + } + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addBody, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, addBody) +{ + zval *new_body; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &new_body, php_http_message_body_class_entry)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_http_message_body_object_t *new_obj = zend_object_store_get_object(new_body TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + php_http_message_body_to_callback(new_obj->body, (php_http_pass_callback_t) php_http_message_body_append, obj->message->body, 0, 0); + } + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeader, 0, 0, 1) + ZEND_ARG_INFO(0, header) + ZEND_ARG_INFO(0, into_class) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getHeader) +{ + char *header_str; + int header_len; + zend_class_entry *header_ce = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!", &header_str, &header_len, &header_ce)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zval *header; + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if ((header = php_http_message_header(obj->message, header_str, header_len, 0))) { + if (!header_ce) { + RETURN_ZVAL(header, 1, 1); + } else if (instanceof_function(header_ce, php_http_header_class_entry TSRMLS_CC)) { + zval *header_name, **argv[2]; + + MAKE_STD_ZVAL(header_name); + ZVAL_STRINGL(header_name, header_str, header_len, 1); + Z_ADDREF_P(header); + + argv[0] = &header_name; + argv[1] = &header; + + object_init_ex(return_value, header_ce); + php_http_method_call(return_value, ZEND_STRL("__construct"), 2, argv, NULL TSRMLS_CC); + + zval_ptr_dtor(&header_name); + zval_ptr_dtor(&header); + + return; + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class '%s' is not as descendant of http\\Header", header_ce->name); + } + } + } + RETURN_FALSE; +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeaders, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getHeaders) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + array_init(return_value); + array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value)); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeader, 0, 0, 1) + ZEND_ARG_INFO(0, header) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setHeader) +{ + zval *zvalue = NULL; + char *name_str; + int name_len; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!", &name_str, &name_len, &zvalue)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (!zvalue) { + zend_symtable_del(&obj->message->hdrs, name, name_len + 1); + } else { + Z_ADDREF_P(zvalue); + zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &zvalue, sizeof(void *), NULL); + } + efree(name); + } + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeaders, 0, 0, 1) + ZEND_ARG_ARRAY_INFO(0, headers, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setHeaders) +{ + zval *new_headers = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &new_headers)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + zend_hash_clean(&obj->message->hdrs); + if (new_headers) { + array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, 0, ARRAY_JOIN_PRETTIFY|ARRAY_JOIN_STRONLY); + } + } + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeader, 0, 0, 2) + ZEND_ARG_INFO(0, header) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, addHeader) +{ + zval *zvalue; + char *name_str; + int name_len; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name_str, &name_len, &zvalue)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); + zval *header; + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + Z_ADDREF_P(zvalue); + if ((header = php_http_message_header(obj->message, name, name_len, 0))) { + convert_to_array(header); + zend_hash_next_index_insert(Z_ARRVAL_P(header), &zvalue, sizeof(void *), NULL); + zval_ptr_dtor(&header); + } else { + zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &zvalue, sizeof(void *), NULL); + } + efree(name); + } + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeaders, 0, 0, 1) + ZEND_ARG_ARRAY_INFO(0, headers, 0) + ZEND_ARG_INFO(0, append) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, addHeaders) +{ + zval *new_headers; + zend_bool append = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY); + } + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getType, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getType) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + RETURN_LONG(obj->message->type); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setType, 0, 0, 1) + ZEND_ARG_INFO(0, type) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setType) +{ + long type; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + php_http_message_set_type(obj->message, type); + } + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getInfo, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getInfo) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + switch (obj->message->type) { + case PHP_HTTP_REQUEST: + Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, "")); + break; + case PHP_HTTP_RESPONSE: + Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, "")); + break; + default: + RETURN_NULL(); + break; + } + Z_TYPE_P(return_value) = IS_STRING; + return; + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setInfo, 0, 0, 1) + ZEND_ARG_INFO(0, http_info) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setInfo) +{ + char *str; + int len; + php_http_message_object_t *obj; + php_http_info_t inf; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (!php_http_info_parse(&inf, str TSRMLS_CC)) { + php_http_throw(bad_header, "Could not parse message info '%s'", str); + return; + } + + php_http_message_set_info(obj->message, &inf); + php_http_info_dtor(&inf); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHttpVersion, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getHttpVersion) +{ + if (SUCCESS == zend_parse_parameters_none()) { + char *str; + size_t len; + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + php_http_version_to_string(&obj->message->http.version, &str, &len, NULL, NULL TSRMLS_CC); + RETURN_STRINGL(str, len, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHttpVersion, 0, 0, 1) + ZEND_ARG_INFO(0, http_version) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setHttpVersion) +{ + char *v_str; + int v_len; + php_http_version_t version; + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &v_str, &v_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + php_http_expect(php_http_version_parse(&version, v_str TSRMLS_CC), unexpected_val, return); + + obj->message->http.version = version; + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseCode, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getResponseCode) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (obj->message->type != PHP_HTTP_RESPONSE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "http\\Message is not if type response"); + RETURN_FALSE; + } + + RETURN_LONG(obj->message->http.info.response.code); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseCode, 0, 0, 1) + ZEND_ARG_INFO(0, response_code) + ZEND_ARG_INFO(0, strict) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setResponseCode) +{ + long code; + zend_bool strict = 1; + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|b", &code, &strict), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (obj->message->type != PHP_HTTP_RESPONSE) { + php_http_throw(bad_method_call, "http\\Message is not of type response", NULL); + return; + } + + if (strict && (code < 100 || code > 599)) { + php_http_throw(invalid_arg, "Invalid response code (100-599): %ld", code); + return; + } + + obj->message->http.info.response.code = code; + STR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(code))); + + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseStatus, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getResponseStatus) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (obj->message->type != PHP_HTTP_RESPONSE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "http\\Message is not of type response"); + } + + if (obj->message->http.info.response.status) { + RETURN_STRING(obj->message->http.info.response.status, 1); + } else { + RETURN_EMPTY_STRING(); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseStatus, 0, 0, 1) + ZEND_ARG_INFO(0, response_status) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setResponseStatus) +{ + char *status; + int status_len; + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &status, &status_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (obj->message->type != PHP_HTTP_RESPONSE) { + php_http_throw(bad_method_call, "http\\Message is not of type response", NULL); + } + + STR_SET(obj->message->http.info.response.status, estrndup(status, status_len)); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestMethod, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getRequestMethod) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (obj->message->type != PHP_HTTP_REQUEST) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "http\\Message is not of type request"); + RETURN_FALSE; + } + + if (obj->message->http.info.request.method) { + RETURN_STRING(obj->message->http.info.request.method, 1); + } else { + RETURN_EMPTY_STRING(); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestMethod, 0, 0, 1) + ZEND_ARG_INFO(0, request_method) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setRequestMethod) +{ + char *method; + int method_len; + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (obj->message->type != PHP_HTTP_REQUEST) { + php_http_throw(bad_method_call, "http\\Message is not of type request", NULL); + return; + } + + if (method_len < 1) { + php_http_throw(invalid_arg, "Cannot set http\\Message's request method to an empty string", NULL); + return; + } + + STR_SET(obj->message->http.info.request.method, estrndup(method, method_len)); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestUrl, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getRequestUrl) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (obj->message->type != PHP_HTTP_REQUEST) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "http\\Message is not of type request"); + RETURN_FALSE; + } + + if (obj->message->http.info.request.url) { + RETURN_STRING(obj->message->http.info.request.url, 1); + } else { + RETURN_EMPTY_STRING(); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestUrl, 0, 0, 1) + ZEND_ARG_INFO(0, url) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, setRequestUrl) +{ + char *url_str; + int url_len; + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url_str, &url_len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (obj->message->type != PHP_HTTP_REQUEST) { + php_http_throw(bad_method_call, "http\\Message is not of type request", NULL); + return; + } + + if (url_len < 1) { + php_http_throw(invalid_arg, "Cannot set http\\Message's request url to an empty string", NULL); + return; + } + + STR_SET(obj->message->http.info.request.url, estrndup(url_str, url_len)); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getParentMessage, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, getParentMessage) +{ + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (!obj->message->parent) { + php_http_throw(unexpected_val, "http\\Message has not parent message", NULL); + return; + } + + RETVAL_OBJVAL(obj->parent->zv, 1); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___toString, 0, 0, 0) +ZEND_END_ARG_INFO(); +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toString, 0, 0, 0) + ZEND_ARG_INFO(0, include_parent) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, toString) +{ + zend_bool include_parent = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + char *string; + size_t length; + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (include_parent) { + php_http_message_serialize(obj->message, &string, &length); + } else { + php_http_message_to_string(obj->message, &string, &length); + } + if (string) { + RETURN_STRINGL(string, length, 0); + } + } + RETURN_EMPTY_STRING(); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toStream, 0, 0, 1) + ZEND_ARG_INFO(0, stream) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, toStream) +{ + zval *zstream; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_stream *s; + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + php_stream_from_zval(s, &zstream); + php_http_message_to_callback(obj->message, (php_http_pass_callback_t) _php_stream_write, s); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toCallback, 0, 0, 1) + ZEND_ARG_INFO(0, callback) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, toCallback) +{ + php_http_pass_fcall_arg_t fcd; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f", &fcd.fci, &fcd.fcc)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + fcd.fcz = getThis(); + Z_ADDREF_P(fcd.fcz); + TSRMLS_SET_CTX(fcd.ts); + + php_http_message_to_callback(obj->message, php_http_pass_fcall_callback, &fcd); + zend_fcall_info_args_clear(&fcd.fci, 1); + + zval_ptr_dtor(&fcd.fcz); + RETURN_ZVAL(getThis(), 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_serialize, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, serialize) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + char *string; + size_t length; + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + php_http_message_serialize(obj->message, &string, &length); + RETURN_STRINGL(string, length, 0); + } + RETURN_EMPTY_STRING(); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_unserialize, 0, 0, 1) + ZEND_ARG_INFO(0, serialized) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, unserialize) +{ + int length; + char *serialized; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &serialized, &length)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_http_message_t *msg; + + if (obj->message) { + php_http_message_dtor(obj->message); + efree(obj->message); + } + if ((msg = php_http_message_parse(NULL, serialized, (size_t) length, 1 TSRMLS_CC))) { + obj->message = msg; + } else { + obj->message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Could not unserialize http\\Message"); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_detach, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, detach) +{ + php_http_message_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + RETVAL_OBJVAL(php_http_message_object_new_ex(obj->zo.ce, php_http_message_copy_ex(obj->message, NULL, 0), NULL TSRMLS_CC), 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_prepend, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, message, http\\Message, 0) + ZEND_ARG_INFO(0, top) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, prepend) +{ + zval *prepend; + zend_bool top = 1; + php_http_message_t *msg[2]; + php_http_message_object_t *obj, *prepend_obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &prepend, php_http_message_class_entry, &top), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + prepend_obj = zend_object_store_get_object(prepend TSRMLS_CC); + PHP_HTTP_MESSAGE_OBJECT_INIT(prepend_obj); + + /* safety check */ + for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) { + for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) { + if (msg[0] == msg[1]) { + php_http_throw(unexpected_val, "Cannot prepend a message located within the same message chain", NULL); + return; + } + } + } + + php_http_message_object_prepend(getThis(), prepend, top TSRMLS_CC); + RETURN_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_reverse, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, reverse) +{ + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + php_http_message_object_reverse(getThis(), return_value TSRMLS_CC); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_isMultipart, 0, 0, 0) + ZEND_ARG_INFO(1, boundary) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, isMultipart) +{ + zval *zboundary = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", &zboundary)) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + char *boundary = NULL; + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + RETVAL_BOOL(php_http_message_is_multipart(obj->message, zboundary ? &boundary : NULL)); + + if (zboundary && boundary) { + zval_dtor(zboundary); + ZVAL_STRING(zboundary, boundary, 0); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_splitMultipartBody, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, splitMultipartBody) +{ + php_http_message_object_t *obj; + php_http_message_t *msg; + char *boundary = NULL; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + if (!php_http_message_is_multipart(obj->message, &boundary)) { + php_http_throw(bad_method_call, "http\\Message is not a multipart message", NULL); + return; + } + + php_http_expect(msg = php_http_message_body_split(obj->message->body, boundary), bad_message, return); + + STR_FREE(boundary); + + RETURN_OBJVAL(php_http_message_object_new_ex(php_http_message_class_entry, msg, NULL TSRMLS_CC), 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_count, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, count) +{ + if (SUCCESS == zend_parse_parameters_none()) { + long i = 0; + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_OBJECT_INIT(obj); + + php_http_message_count(i, obj->message); + RETURN_LONG(i); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_rewind, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, rewind) +{ + if (SUCCESS == zend_parse_parameters_none()) { + zval *zobj = getThis(); + php_http_message_object_t *obj = zend_object_store_get_object(zobj TSRMLS_CC); + + if (obj->iterator) { + zval_ptr_dtor(&obj->iterator); + } + Z_ADDREF_P(zobj); + obj->iterator = zobj; + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_valid, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, valid) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_BOOL(obj->iterator != NULL); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_next, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, next) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (obj->iterator) { + php_http_message_object_t *itr = zend_object_store_get_object(obj->iterator TSRMLS_CC); + + if (itr && itr->parent) { + zval *old = obj->iterator; + MAKE_STD_ZVAL(obj->iterator); + ZVAL_OBJVAL(obj->iterator, itr->parent->zv, 1); + zval_ptr_dtor(&old); + } else { + zval_ptr_dtor(&obj->iterator); + obj->iterator = NULL; + } + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_key, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, key) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_LONG(obj->iterator ? obj->iterator->value.obj.handle:0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_current, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpMessage, current) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (obj->iterator) { + RETURN_ZVAL(obj->iterator, 1, 0); + } + } +} + +static zend_function_entry php_http_message_methods[] = { + PHP_ME(HttpMessage, __construct, ai_HttpMessage___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpMessage, getBody, ai_HttpMessage_getBody, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setBody, ai_HttpMessage_setBody, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, addBody, ai_HttpMessage_addBody, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getHeader, ai_HttpMessage_getHeader, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setHeader, ai_HttpMessage_setHeader, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, addHeader, ai_HttpMessage_addHeader, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getHeaders, ai_HttpMessage_getHeaders, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setHeaders, ai_HttpMessage_setHeaders, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, addHeaders, ai_HttpMessage_addHeaders, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getType, ai_HttpMessage_getType, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setType, ai_HttpMessage_setType, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getInfo, ai_HttpMessage_getInfo, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setInfo, ai_HttpMessage_setInfo, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getResponseCode, ai_HttpMessage_getResponseCode, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setResponseCode, ai_HttpMessage_setResponseCode, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getResponseStatus, ai_HttpMessage_getResponseStatus, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setResponseStatus, ai_HttpMessage_setResponseStatus, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getRequestMethod, ai_HttpMessage_getRequestMethod, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setRequestMethod, ai_HttpMessage_setRequestMethod, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getRequestUrl, ai_HttpMessage_getRequestUrl, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setRequestUrl, ai_HttpMessage_setRequestUrl, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getHttpVersion, ai_HttpMessage_getHttpVersion, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, setHttpVersion, ai_HttpMessage_setHttpVersion, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getParentMessage, ai_HttpMessage_getParentMessage, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, toString, ai_HttpMessage_toString, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, toCallback, ai_HttpMessage_toCallback, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, toStream, ai_HttpMessage_toStream, ZEND_ACC_PUBLIC) + + /* implements Countable */ + PHP_ME(HttpMessage, count, ai_HttpMessage_count, ZEND_ACC_PUBLIC) + + /* implements Serializable */ + PHP_ME(HttpMessage, serialize, ai_HttpMessage_serialize, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, unserialize, ai_HttpMessage_unserialize, ZEND_ACC_PUBLIC) + + /* implements Iterator */ + PHP_ME(HttpMessage, rewind, ai_HttpMessage_rewind, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, valid, ai_HttpMessage_valid, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, current, ai_HttpMessage_current, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, key, ai_HttpMessage_key, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, next, ai_HttpMessage_next, ZEND_ACC_PUBLIC) + + ZEND_MALIAS(HttpMessage, __toString, toString, ai_HttpMessage___toString, ZEND_ACC_PUBLIC) + + PHP_ME(HttpMessage, detach, ai_HttpMessage_detach, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, prepend, ai_HttpMessage_prepend, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, reverse, ai_HttpMessage_reverse, ZEND_ACC_PUBLIC) + + PHP_ME(HttpMessage, isMultipart, ai_HttpMessage_isMultipart, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, splitMultipartBody, ai_HttpMessage_splitMultipartBody, ZEND_ACC_PUBLIC) + + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_message_class_entry; + +PHP_MINIT_FUNCTION(http_message) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "Message", php_http_message_methods); + php_http_message_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + php_http_message_class_entry->create_object = php_http_message_object_new; + memcpy(&php_http_message_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + php_http_message_object_handlers.clone_obj = php_http_message_object_clone; + php_http_message_object_handlers.read_property = php_http_message_object_read_prop; + php_http_message_object_handlers.write_property = php_http_message_object_write_prop; + php_http_message_object_handlers.get_properties = php_http_message_object_get_props; + php_http_message_object_handlers.get_property_ptr_ptr = NULL; + + zend_class_implements(php_http_message_class_entry TSRMLS_CC, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator); + + zend_hash_init(&php_http_message_object_prophandlers, 9, NULL, NULL, 1); + zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("type"), PHP_HTTP_NONE, ZEND_ACC_PROTECTED TSRMLS_CC); + php_http_message_object_add_prophandler(ZEND_STRL("type"), php_http_message_object_prophandler_get_type, php_http_message_object_prophandler_set_type); + zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("body"), ZEND_ACC_PROTECTED TSRMLS_CC); + php_http_message_object_add_prophandler(ZEND_STRL("body"), php_http_message_object_prophandler_get_body, php_http_message_object_prophandler_set_body); + zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestMethod"), "", ZEND_ACC_PROTECTED TSRMLS_CC); + php_http_message_object_add_prophandler(ZEND_STRL("requestMethod"), php_http_message_object_prophandler_get_request_method, php_http_message_object_prophandler_set_request_method); + zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestUrl"), "", ZEND_ACC_PROTECTED TSRMLS_CC); + php_http_message_object_add_prophandler(ZEND_STRL("requestUrl"), php_http_message_object_prophandler_get_request_url, php_http_message_object_prophandler_set_request_url); + zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("responseStatus"), "", ZEND_ACC_PROTECTED TSRMLS_CC); + php_http_message_object_add_prophandler(ZEND_STRL("responseStatus"), php_http_message_object_prophandler_get_response_status, php_http_message_object_prophandler_set_response_status); + zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("responseCode"), 0, ZEND_ACC_PROTECTED TSRMLS_CC); + php_http_message_object_add_prophandler(ZEND_STRL("responseCode"), php_http_message_object_prophandler_get_response_code, php_http_message_object_prophandler_set_response_code); + zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("httpVersion"), ZEND_ACC_PROTECTED TSRMLS_CC); + php_http_message_object_add_prophandler(ZEND_STRL("httpVersion"), php_http_message_object_prophandler_get_http_version, php_http_message_object_prophandler_set_http_version); + zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("headers"), ZEND_ACC_PROTECTED TSRMLS_CC); + php_http_message_object_add_prophandler(ZEND_STRL("headers"), php_http_message_object_prophandler_get_headers, php_http_message_object_prophandler_set_headers); + zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("parentMessage"), ZEND_ACC_PROTECTED TSRMLS_CC); + php_http_message_object_add_prophandler(ZEND_STRL("parentMessage"), php_http_message_object_prophandler_get_parent_message, php_http_message_object_prophandler_set_parent_message); + + zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_NONE"), PHP_HTTP_NONE TSRMLS_CC); + zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_REQUEST"), PHP_HTTP_REQUEST TSRMLS_CC); + zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_RESPONSE"), PHP_HTTP_RESPONSE TSRMLS_CC); + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(http_message) +{ + zend_hash_destroy(&php_http_message_object_prophandlers); + + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_message.h b/php_http_message.h new file mode 100644 index 0000000..32af834 --- /dev/null +++ b/php_http_message.h @@ -0,0 +1,102 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_MESSAGE_H +#define PHP_HTTP_MESSAGE_H + +#include "php_http_message_body.h" + +/* required minimum length of an HTTP message "HTTP/1.1" */ +#define PHP_HTTP_MESSAGE_MIN_SIZE 8 +#define PHP_HTTP_MESSAGE_TYPE(TYPE, msg) ((msg) && ((msg)->type == PHP_HTTP_ ##TYPE)) + +typedef php_http_info_type_t php_http_message_type_t; +typedef struct php_http_message php_http_message_t; + +struct php_http_message { + PHP_HTTP_INFO_IMPL(http, type) + HashTable hdrs; + php_http_message_body_t *body; + php_http_message_t *parent; + void *opaque; +#ifdef ZTS + void ***ts; +#endif +}; + +PHP_HTTP_API zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info TSRMLS_DC); + +PHP_HTTP_API php_http_message_t *php_http_message_init(php_http_message_t *m, php_http_message_type_t t, php_http_message_body_t *body TSRMLS_DC); +PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *m, php_http_message_type_t t TSRMLS_DC); +PHP_HTTP_API php_http_message_t *php_http_message_copy(php_http_message_t *from, php_http_message_t *to); +PHP_HTTP_API php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents); +PHP_HTTP_API void php_http_message_dtor(php_http_message_t *message); +PHP_HTTP_API void php_http_message_free(php_http_message_t **message); + +PHP_HTTP_API void php_http_message_set_type(php_http_message_t *m, php_http_message_type_t t); +PHP_HTTP_API void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info); + +PHP_HTTP_API void php_http_message_update_headers(php_http_message_t *msg); + +PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len, int join); +PHP_HTTP_API zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary); + +PHP_HTTP_API void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length); +PHP_HTTP_API void php_http_message_to_struct(php_http_message_t *msg, zval *strct); +PHP_HTTP_API void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg); + +PHP_HTTP_API void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length); +PHP_HTTP_API php_http_message_t *php_http_message_reverse(php_http_message_t *msg); +PHP_HTTP_API php_http_message_t *php_http_message_zip(php_http_message_t *one, php_http_message_t *two); + +#define php_http_message_count(c, m) \ +{ \ + php_http_message_t *__tmp_msg = (m); \ + for (c = 0; __tmp_msg; __tmp_msg = __tmp_msg->parent, ++(c)); \ +} + +PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy TSRMLS_DC); + +typedef struct php_http_message_object { + zend_object zo; + zend_object_value zv; + php_http_message_t *message; + struct php_http_message_object *parent; + php_http_message_body_object_t *body; + zval *iterator; +} php_http_message_object_t; + +PHP_HTTP_API zend_class_entry *php_http_message_class_entry; + +PHP_MINIT_FUNCTION(http_message); +PHP_MSHUTDOWN_FUNCTION(http_message); + +void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top /* = 1 */ TSRMLS_DC); +void php_http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC); +STATUS php_http_message_object_set_body(php_http_message_object_t *obj, zval *zbody TSRMLS_DC); + +zend_object_value php_http_message_object_new(zend_class_entry *ce TSRMLS_DC); +zend_object_value php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg, php_http_message_object_t **ptr TSRMLS_DC); +zend_object_value php_http_message_object_clone(zval *object TSRMLS_DC); +void php_http_message_object_free(void *object TSRMLS_DC); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_message_api.h b/php_http_message_api.h deleted file mode 100644 index 868a86b..0000000 --- a/php_http_message_api.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_MESSAGE_API_H -#define PHP_HTTP_MESSAGE_API_H - -#include "php_http_info_api.h" - -typedef enum _http_message_type_t { - HTTP_MSG_NONE = 0, - HTTP_MSG_REQUEST = IS_HTTP_REQUEST, - HTTP_MSG_RESPONSE = IS_HTTP_RESPONSE, -} http_message_type; - -typedef struct _http_message_t http_message; - -struct _http_message_t { - phpstr body; - HashTable hdrs; - http_message_type type; - struct http_info http; - http_message *parent; -}; - -/* required minimum length of an HTTP message "HTTP/1.1" */ -#define HTTP_MSG_MIN_SIZE 8 - -/* shorthand for type checks */ -#define HTTP_MSG_TYPE(TYPE, msg) ((msg) && ((msg)->type == HTTP_MSG_ ##TYPE)) - -#define http_message_new() http_message_init_ex(NULL, 0) -#define http_message_init(m) http_message_init_ex((m), 0) -#define http_message_init_ex(m, t) _http_message_init_ex((m), (t) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) -#define http_message_init_rel(m, t) _http_message_init_ex((m), (t) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC) -PHP_HTTP_API http_message *_http_message_init_ex(http_message *m, http_message_type t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); -#define http_message_init_env(m, t) _http_message_init_env((m), (t) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) -PHP_HTTP_API http_message *_http_message_init_env(http_message *m, http_message_type t TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); - -#define http_message_set_type(m, t) _http_message_set_type((m), (t)) -PHP_HTTP_API void _http_message_set_type(http_message *m, http_message_type t); - -#define http_message_set_info(m, i) _http_message_set_info((m), (i)) -PHP_HTTP_API void _http_message_set_info(http_message *message, http_info *info); - -#define http_message_header(m, h) _http_message_header_ex((m), (h), sizeof(h), 1) -#define http_message_header_ex _http_message_header_ex -static inline zval *_http_message_header_ex(http_message *msg, char *key_str, size_t key_len, int join) -{ - zval **header; - if (SUCCESS == zend_hash_find(&msg->hdrs, key_str, key_len, (void *) &header)) { - if (join && Z_TYPE_PP(header) == IS_ARRAY) { - zval *header_str, **val; - HashPosition pos; - phpstr str; - - phpstr_init(&str); - MAKE_STD_ZVAL(header_str); - FOREACH_VAL(pos, *header, val) { - phpstr_appendf(&str, PHPSTR_LEN(&str) ? ", %s":"%s", Z_STRVAL_PP(val)); - } - phpstr_fix(&str); - ZVAL_STRINGL(header_str, PHPSTR_VAL(&str), PHPSTR_LEN(&str), 0); - return header_str; - } else { - ZVAL_ADDREF(*header); - return *header; - } - } - return NULL; -} - -#define http_message_count(c, m) \ -{ \ - http_message *__tmp_msg = (m); \ - for (c = 0; __tmp_msg; __tmp_msg = __tmp_msg->parent, ++(c)); \ -} - -#define http_message_parse(m, l) http_message_parse_ex(NULL, (m), (l)) -#define http_message_parse_ex(h, m, l) _http_message_parse_ex((h), (m), (l) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -#define http_message_parse_rel(h, m, l) _http_message_parse_ex((h), (m), (l) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC TSRMLS_CC) -PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char *message, size_t length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); - -#define http_message_tostring(m, s, l) _http_message_tostring((m), (s), (l)) -PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length); - -#define http_message_serialize(m, s, l) _http_message_serialize((m), (s), (l)) -PHP_HTTP_API void _http_message_serialize(http_message *message, char **string, size_t *length); - -#define http_message_reverse(m) _http_message_reverse(m) -PHP_HTTP_API http_message *_http_message_reverse(http_message *msg); - -#define http_message_interconnect(m1, m2) _http_message_interconnect((m1), (m2)) -PHP_HTTP_API http_message *_http_message_interconnect(http_message *m1, http_message *m2); - -#define http_message_tostruct_recursive(m, s) _http_message_tostruct_recursive((m), (s) TSRMLS_CC) -PHP_HTTP_API void _http_message_tostruct_recursive(http_message *msg, zval *strct TSRMLS_DC); - -#define http_message_send(m) _http_message_send((m) TSRMLS_CC) -PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC); - -#define http_message_dup(m) _http_message_dup((m) TSRMLS_CC) -PHP_HTTP_API http_message *_http_message_dup(http_message *msg TSRMLS_DC); - -#define http_message_dtor(m) _http_message_dtor((m)) -PHP_HTTP_API void _http_message_dtor(http_message *message); - -#define http_message_free(m) _http_message_free((m)) -PHP_HTTP_API void _http_message_free(http_message **message); - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_message_body.c b/php_http_message_body.c new file mode 100644 index 0000000..2749fac --- /dev/null +++ b/php_http_message_body.c @@ -0,0 +1,926 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#include + +#define BOUNDARY_OPEN(body) \ + do {\ + size_t size = php_http_message_body_size(body); \ + if (size) { \ + php_stream_truncate_set_size(php_http_message_body_stream(body), size - lenof("--" PHP_HTTP_CRLF)); \ + php_http_message_body_append(body, ZEND_STRL(PHP_HTTP_CRLF)); \ + } else { \ + php_http_message_body_appendf(body, "--%s" PHP_HTTP_CRLF, php_http_message_body_boundary(body)); \ + } \ + } while(0) + +#define BOUNDARY_CLOSE(body) \ + php_http_message_body_appendf(body, PHP_HTTP_CRLF "--%s--" PHP_HTTP_CRLF, php_http_message_body_boundary(body)) + +static STATUS add_recursive_fields(php_http_message_body_t *body, const char *name, zval *value); +static STATUS add_recursive_files(php_http_message_body_t *body, const char *name, zval *value); + +php_http_message_body_t *php_http_message_body_init(php_http_message_body_t **body_ptr, php_stream *stream TSRMLS_DC) +{ + php_http_message_body_t *body; + + if (body_ptr && *body_ptr) { + body = *body_ptr; + ++body->refcount; + return body; + } + + body = ecalloc(1, sizeof(php_http_message_body_t)); + body->refcount = 1; + + if (stream) { + php_stream_auto_cleanup(stream); + body->stream_id = php_stream_get_resource_id(stream); + zend_list_addref(body->stream_id); + } else { + stream = php_stream_temp_create(TEMP_STREAM_DEFAULT, 0xffff); + php_stream_auto_cleanup(stream); + body->stream_id = php_stream_get_resource_id(stream); + } + TSRMLS_SET_CTX(body->ts); + + return body; +} + +unsigned php_http_message_body_addref(php_http_message_body_t *body) +{ + return ++body->refcount; +} + +php_http_message_body_t *php_http_message_body_copy(php_http_message_body_t *from, php_http_message_body_t *to) +{ + if (from) { + TSRMLS_FETCH_FROM_CTX(from->ts); + + if (to) { + php_stream_truncate_set_size(php_http_message_body_stream(to), 0); + } else { + to = php_http_message_body_init(NULL, NULL TSRMLS_CC); + } + php_http_message_body_to_stream(from, php_http_message_body_stream(to), 0, 0); + + if (to->boundary) { + efree(to->boundary); + } + if (from->boundary) { + to->boundary = estrdup(from->boundary); + } + } else { + to = NULL; + } + return to; +} + +void php_http_message_body_free(php_http_message_body_t **body_ptr) +{ + if (*body_ptr) { + php_http_message_body_t *body = *body_ptr; + + if (!--body->refcount) { + TSRMLS_FETCH_FROM_CTX(body->ts); + /* NOFIXME: shows leakinfo in DEBUG mode */ + zend_list_delete(body->stream_id); + STR_FREE(body->boundary); + efree(body); + } + *body_ptr = NULL; + } +} + +const php_stream_statbuf *php_http_message_body_stat(php_http_message_body_t *body) +{ + TSRMLS_FETCH_FROM_CTX(body->ts); + php_stream_stat(php_http_message_body_stream(body), &body->ssb); + return &body->ssb; +} + +const char *php_http_message_body_boundary(php_http_message_body_t *body) +{ + if (!body->boundary) { + union { double dbl; int num[2]; } data; + TSRMLS_FETCH_FROM_CTX(body->ts); + + data.dbl = php_combined_lcg(TSRMLS_C); + spprintf(&body->boundary, 0, "%x.%x", data.num[0], data.num[1]); + } + return body->boundary; +} + +char *php_http_message_body_etag(php_http_message_body_t *body) +{ + const php_stream_statbuf *ssb = php_http_message_body_stat(body); + TSRMLS_FETCH_FROM_CTX(body->ts); + + /* real file or temp buffer ? */ + if (ssb && ssb->sb.st_mtime) { + char *etag; + + spprintf(&etag, 0, "%lx-%lx-%lx", ssb->sb.st_ino, ssb->sb.st_mtime, ssb->sb.st_size); + return etag; + } else { + php_http_etag_t *etag = php_http_etag_init(PHP_HTTP_G->env.etag_mode TSRMLS_CC); + + if (etag) { + php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_etag_update, etag, 0, 0); + return php_http_etag_finish(etag); + } else { + return NULL; + } + } +} + +void php_http_message_body_to_string(php_http_message_body_t *body, char **buf, size_t *len, off_t offset, size_t forlen) +{ + php_stream *s = php_http_message_body_stream(body); + TSRMLS_FETCH_FROM_CTX(body->ts); + + php_stream_seek(s, offset, SEEK_SET); + if (!forlen) { + forlen = -1; + } + *len = php_stream_copy_to_mem(s, buf, forlen, 0); +} + +STATUS php_http_message_body_to_stream(php_http_message_body_t *body, php_stream *dst, off_t offset, size_t forlen) +{ + php_stream *s = php_http_message_body_stream(body); + TSRMLS_FETCH_FROM_CTX(body->ts); + + php_stream_seek(s, offset, SEEK_SET); + + if (!forlen) { + forlen = -1; + } + return php_stream_copy_to_stream_ex(s, dst, forlen, NULL); +} + +STATUS php_http_message_body_to_callback(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, off_t offset, size_t forlen) +{ + php_stream *s = php_http_message_body_stream(body); + char *buf = emalloc(0x1000); + TSRMLS_FETCH_FROM_CTX(body->ts); + + php_stream_seek(s, offset, SEEK_SET); + + if (!forlen) { + forlen = -1; + } + while (!php_stream_eof(s)) { + size_t read = php_stream_read(s, buf, MIN(forlen, 0x1000)); + + if (read) { + if (-1 == cb(cb_arg, buf, read)) { + return FAILURE; + } + } + + if (read < MIN(forlen, sizeof(buf))) { + break; + } + + if (forlen && !(forlen -= read)) { + break; + } + } + efree(buf); + + return SUCCESS; +} + +size_t php_http_message_body_append(php_http_message_body_t *body, const char *buf, size_t len) +{ + php_stream *s; + size_t written; + TSRMLS_FETCH_FROM_CTX(body->ts); + + if (!(s = php_http_message_body_stream(body))) { + return -1; + } + + if (s->ops->seek) { + php_stream_seek(s, 0, SEEK_END); + } + + written = php_stream_write(s, buf, len); + + if (written != len) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to append %zu bytes to body; wrote %zu", len, written); + } + + return len; +} + +size_t php_http_message_body_appendf(php_http_message_body_t *body, const char *fmt, ...) +{ + va_list argv; + char *print_str; + size_t print_len; + + va_start(argv, fmt); + print_len = vspprintf(&print_str, 0, fmt, argv); + va_end(argv); + + print_len = php_http_message_body_append(body, print_str, print_len); + efree(print_str); + + return print_len; +} + +STATUS php_http_message_body_add_form(php_http_message_body_t *body, HashTable *fields, HashTable *files) +{ + zval tmp; + + if (fields) { + INIT_PZVAL_ARRAY(&tmp, fields); + if (SUCCESS != add_recursive_fields(body, NULL, &tmp)) { + return FAILURE; + } + } + if (files) { + INIT_PZVAL_ARRAY(&tmp, files); + if (SUCCESS != add_recursive_files(body, NULL, &tmp)) { + return FAILURE; + } + } + + return SUCCESS; +} + +void php_http_message_body_add_part(php_http_message_body_t *body, php_http_message_t *part) +{ + TSRMLS_FETCH_FROM_CTX(body->ts); + + BOUNDARY_OPEN(body); + php_http_message_to_callback(part, (php_http_pass_callback_t) php_http_message_body_append, body); + BOUNDARY_CLOSE(body); +} + + +STATUS php_http_message_body_add_form_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len) +{ + char *safe_name; + TSRMLS_FETCH_FROM_CTX(body->ts); + + safe_name = php_addslashes(estrdup(name), strlen(name), NULL, 1 TSRMLS_CC); + + BOUNDARY_OPEN(body); + php_http_message_body_appendf( + body, + "Content-Disposition: form-data; name=\"%s\"" PHP_HTTP_CRLF + "" PHP_HTTP_CRLF, + safe_name + ); + php_http_message_body_append(body, value_str, value_len); + BOUNDARY_CLOSE(body); + + efree(safe_name); + return SUCCESS; +} + +STATUS php_http_message_body_add_form_file(php_http_message_body_t *body, const char *name, const char *ctype, const char *path, php_stream *in) +{ + char *safe_name, *path_dup = estrdup(path), *bname; + size_t bname_len; + TSRMLS_FETCH_FROM_CTX(body->ts); + + safe_name = php_addslashes(estrdup(name), strlen(name), NULL, 1 TSRMLS_CC); + + php_basename(path_dup, strlen(path_dup), NULL, 0, &bname, &bname_len TSRMLS_CC); + + BOUNDARY_OPEN(body); + php_http_message_body_appendf( + body, + "Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"" PHP_HTTP_CRLF + "Content-Transfer-Encoding: binary" PHP_HTTP_CRLF + "Content-Type: %s" PHP_HTTP_CRLF + PHP_HTTP_CRLF, + safe_name, bname, ctype + ); + php_stream_copy_to_stream_ex(in, php_http_message_body_stream(body), PHP_STREAM_COPY_ALL, NULL); + BOUNDARY_CLOSE(body); + + efree(safe_name); + efree(path_dup); + efree(bname); + + return SUCCESS; +} + +static inline char *format_key(uint type, char *str, ulong num, const char *prefix) { + char *new_key = NULL; + + if (prefix && *prefix) { + if (type == HASH_KEY_IS_STRING) { + spprintf(&new_key, 0, "%s[%s]", prefix, str); + } else { + spprintf(&new_key, 0, "%s[%lu]", prefix, num); + } + } else if (type == HASH_KEY_IS_STRING) { + new_key = estrdup(str); + } else { + new_key = estrdup(""); + } + + return new_key; +} + +static STATUS add_recursive_fields(php_http_message_body_t *body, const char *name, zval *value) +{ + if (Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) { + zval **val; + HashTable *ht; + HashPosition pos; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + TSRMLS_FETCH_FROM_CTX(body->ts); + + ht = HASH_OF(value); + if (!ht->nApplyCount) { + ++ht->nApplyCount; + FOREACH_KEYVAL(pos, value, key, val) { + char *str = format_key(key.type, key.str, key.num, name); + if (SUCCESS != add_recursive_fields(body, str, *val)) { + efree(str); + ht->nApplyCount--; + return FAILURE; + } + efree(str); + } + --ht->nApplyCount; + } + } else { + zval *cpy = php_http_ztyp(IS_STRING, value); + php_http_message_body_add_form_field(body, name, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); + zval_ptr_dtor(&cpy); + } + + return SUCCESS; +} + +static STATUS add_recursive_files(php_http_message_body_t *body, const char *name, zval *value) +{ + zval **zdata = NULL, **zfile, **zname, **ztype; + HashTable *ht; + TSRMLS_FETCH_FROM_CTX(body->ts); + + if (Z_TYPE_P(value) != IS_ARRAY && Z_TYPE_P(value) != IS_OBJECT) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array or object (name, type, file) for message body file to add"); + return FAILURE; + } + + ht = HASH_OF(value); + + if ((SUCCESS != zend_hash_find(ht, ZEND_STRS("name"), (void *) &zname)) + || (SUCCESS != zend_hash_find(ht, ZEND_STRS("type"), (void *) &ztype)) + || (SUCCESS != zend_hash_find(ht, ZEND_STRS("file"), (void *) &zfile)) + ) { + zval **val; + HashPosition pos; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + + if (!ht->nApplyCount) { + ++ht->nApplyCount; + FOREACH_HASH_KEYVAL(pos, ht, key, val) { + if (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT) { + char *str = format_key(key.type, key.str, key.num, name); + + if (SUCCESS != add_recursive_files(body, str, *val)) { + efree(str); + --ht->nApplyCount; + return FAILURE; + } + efree(str); + } + } + --ht->nApplyCount; + } + return SUCCESS; + } else { + php_stream *stream; + zval *zfc = php_http_ztyp(IS_STRING, *zfile); + + if (SUCCESS == zend_hash_find(ht, ZEND_STRS("data"), (void *) &zdata)) { + if (Z_TYPE_PP(zdata) == IS_RESOURCE) { + php_stream_from_zval_no_verify(stream, zdata); + } else { + zval *tmp = php_http_ztyp(IS_STRING, *zdata); + + stream = php_stream_memory_open(TEMP_STREAM_READONLY, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + zval_ptr_dtor(&tmp); + } + } else { + stream = php_stream_open_wrapper(Z_STRVAL_P(zfc), "r", REPORT_ERRORS|USE_PATH, NULL); + } + + if (!stream) { + zval_ptr_dtor(&zfc); + return FAILURE; + } else { + zval *znc = php_http_ztyp(IS_STRING, *zname), *ztc = php_http_ztyp(IS_STRING, *ztype); + char *key = format_key(HASH_KEY_IS_STRING, Z_STRVAL_P(znc), 0, name); + STATUS ret = php_http_message_body_add_form_file(body, key, Z_STRVAL_P(ztc), Z_STRVAL_P(zfc), stream); + + efree(key); + zval_ptr_dtor(&znc); + zval_ptr_dtor(&ztc); + zval_ptr_dtor(&zfc); + if (!zdata || Z_TYPE_PP(zdata) != IS_RESOURCE) { + php_stream_close(stream); + } + return ret; + } + + } +} + +struct splitbody_arg { + php_http_buffer_t buf; + php_http_message_parser_t *parser; + char *boundary_str; + size_t boundary_len; + size_t consumed; +}; + +static size_t splitbody(void *opaque, char *buf, size_t len TSRMLS_DC) +{ + struct splitbody_arg *arg = opaque; + const char *boundary = NULL; + size_t consumed = 0; + int first_boundary; + + do { + first_boundary = !(consumed || arg->consumed); + + if ((boundary = php_http_locate_str(buf, len, arg->boundary_str + first_boundary, arg->boundary_len - first_boundary))) { + size_t real_boundary_len = arg->boundary_len - 1, cut; + const char *real_boundary = boundary + !first_boundary; + int eol_len = 0; + + if (buf + len <= real_boundary + real_boundary_len) { + /* if we just have enough data for the boundary, it's just a byte too less */ + arg->consumed += consumed; + return consumed; + } + + if (!first_boundary) { + /* this is not the first boundary, read rest of this message */ + php_http_buffer_append(&arg->buf, buf, real_boundary - buf); + php_http_message_parser_parse(arg->parser, &arg->buf, 0, &arg->parser->message); + } + + /* move after the boundary */ + cut = real_boundary - buf + real_boundary_len; + buf += cut; + len -= cut; + consumed += cut; + + if (buf == php_http_locate_bin_eol(buf, len, &eol_len)) { + /* skip CRLF */ + buf += eol_len; + len -= eol_len; + consumed += eol_len; + + if (!first_boundary) { + /* advance messages */ + php_http_message_t *msg; + + msg = php_http_message_init(NULL, 0, NULL TSRMLS_CC); + msg->parent = arg->parser->message; + arg->parser->message = msg; + } + } else { + /* is this the last boundary? */ + if (*buf == '-') { + /* ignore the rest */ + consumed += len; + len = 0; + } else { + /* let this be garbage */ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Malformed multipart boundary at pos %zu", consumed); + return -1; + } + } + } + } while (boundary && len); + + /* let there be room for the next boundary */ + if (len > arg->boundary_len) { + consumed += len - arg->boundary_len; + php_http_buffer_append(&arg->buf, buf, len - arg->boundary_len); + php_http_message_parser_parse(arg->parser, &arg->buf, 0, &arg->parser->message); + } + + arg->consumed += consumed; + return consumed; +} + +php_http_message_t *php_http_message_body_split(php_http_message_body_t *body, const char *boundary) +{ + php_stream *s = php_http_message_body_stream(body); + php_http_buffer_t *tmp = NULL; + php_http_message_t *msg = NULL; + struct splitbody_arg arg; + TSRMLS_FETCH_FROM_CTX(body->ts); + + php_http_buffer_init(&arg.buf); + arg.parser = php_http_message_parser_init(NULL TSRMLS_CC); + arg.boundary_len = spprintf(&arg.boundary_str, 0, "\n--%s", boundary); + arg.consumed = 0; + + php_stream_rewind(s); + while (!php_stream_eof(s)) { + php_http_buffer_passthru(&tmp, 0x1000, (php_http_buffer_pass_func_t) _php_stream_read, s, splitbody, &arg TSRMLS_CC); + } + + msg = arg.parser->message; + arg.parser->message = NULL; + + php_http_buffer_free(&tmp); + php_http_message_parser_free(&arg.parser); + php_http_buffer_dtor(&arg.buf); + STR_FREE(arg.boundary_str); + + return msg; +} + +static zend_object_handlers php_http_message_body_object_handlers; + +zend_object_value php_http_message_body_object_new(zend_class_entry *ce TSRMLS_DC) +{ + return php_http_message_body_object_new_ex(ce, NULL, NULL TSRMLS_CC); +} + +zend_object_value php_http_message_body_object_new_ex(zend_class_entry *ce, php_http_message_body_t *body, php_http_message_body_object_t **ptr TSRMLS_DC) +{ + php_http_message_body_object_t *o; + + o = ecalloc(1, sizeof(php_http_message_body_object_t)); + zend_object_std_init((zend_object *) o, php_http_message_body_class_entry TSRMLS_CC); + object_properties_init((zend_object *) o, ce); + + if (ptr) { + *ptr = o; + } + + if (body) { + o->body = body; + } + + o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_message_body_object_free, NULL TSRMLS_CC); + o->zv.handlers = &php_http_message_body_object_handlers; + + return o->zv; +} + +zend_object_value php_http_message_body_object_clone(zval *object TSRMLS_DC) +{ + zend_object_value new_ov; + php_http_message_body_object_t *new_obj = NULL; + php_http_message_body_object_t *old_obj = zend_object_store_get_object(object TSRMLS_CC); + php_http_message_body_t *body = php_http_message_body_copy(old_obj->body, NULL); + + new_ov = php_http_message_body_object_new_ex(old_obj->zo.ce, body, &new_obj TSRMLS_CC); + zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(object) TSRMLS_CC); + + return new_ov; +} + +void php_http_message_body_object_free(void *object TSRMLS_DC) +{ + php_http_message_body_object_t *obj = object; + + php_http_message_body_free(&obj->body); + zend_object_std_dtor((zend_object *) obj TSRMLS_CC); + efree(obj); +} + +#define PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj) \ + do { \ + if (!obj->body) { \ + obj->body = php_http_message_body_init(NULL, NULL TSRMLS_CC); \ + } \ + } while(0) + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody___construct, 0, 0, 0) + ZEND_ARG_INFO(0, stream) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, __construct) +{ + php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zval *zstream = NULL; + php_stream *stream; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r!", &zstream), invalid_arg, return); + + if (zstream) { + php_http_expect(php_stream_from_zval_no_verify(stream, &zstream), unexpected_val, return); + + if (obj->body) { + php_http_message_body_free(&obj->body); + } + obj->body = php_http_message_body_init(NULL, stream TSRMLS_CC); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody___toString, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, __toString) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + char *str; + size_t len; + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + php_http_message_body_to_string(obj->body, &str, &len, 0, 0); + if (str) { + RETURN_STRINGL(str, len, 0); + } + } + RETURN_EMPTY_STRING(); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_unserialize, 0, 0, 1) + ZEND_ARG_INFO(0, serialized) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, unserialize) +{ + char *us_str; + int us_len; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &us_str, &us_len)) { + php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_stream *s = php_stream_memory_open(0, us_str, us_len); + + obj->body = php_http_message_body_init(NULL, s TSRMLS_CC); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_toStream, 0, 0, 1) + ZEND_ARG_INFO(0, stream) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, maxlen) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, toStream) +{ + zval *zstream; + long offset = 0, forlen = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ll", &zstream, &offset, &forlen)) { + php_stream *stream; + php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + php_stream_from_zval(stream, &zstream); + php_http_message_body_to_stream(obj->body, stream, offset, forlen); + RETURN_ZVAL(getThis(), 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_toCallback, 0, 0, 1) + ZEND_ARG_INFO(0, callback) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, maxlen) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, toCallback) +{ + php_http_pass_fcall_arg_t fcd; + long offset = 0, forlen = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f|ll", &fcd.fci, &fcd.fcc, &offset, &forlen)) { + php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + fcd.fcz = getThis(); + Z_ADDREF_P(fcd.fcz); + TSRMLS_SET_CTX(fcd.ts); + + php_http_message_body_to_callback(obj->body, php_http_pass_fcall_callback, &fcd, offset, forlen); + zend_fcall_info_args_clear(&fcd.fci, 1); + + zval_ptr_dtor(&fcd.fcz); + RETURN_ZVAL(getThis(), 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_getResource, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, getResource) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + zend_list_addref(obj->body->stream_id); + RETVAL_RESOURCE(obj->body->stream_id); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_getBoundary, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, getBoundary) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_body_object_t * obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + if (obj->body->boundary) { + RETURN_STRING(obj->body->boundary, 1); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_append, 0, 0, 1) + ZEND_ARG_INFO(0, string) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, append) +{ + char *str; + int len; + php_http_message_body_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + php_http_expect(len == php_http_message_body_append(obj->body, str, len), runtime, return); + + RETURN_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_addForm, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, fields, 1) + ZEND_ARG_ARRAY_INFO(0, files, 1) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, addForm) +{ + HashTable *fields = NULL, *files = NULL; + php_http_message_body_object_t *obj; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|h!h!", &fields, &files), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + php_http_expect(SUCCESS == php_http_message_body_add_form(obj->body, fields, files), runtime, return); + + RETURN_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_addPart, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, message, http\\Message, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, addPart) +{ + zval *zobj; + php_http_message_body_object_t *obj; + php_http_message_object_t *mobj; + zend_error_handling zeh; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobj, php_http_message_class_entry), invalid_arg, return); + + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + mobj = zend_object_store_get_object(zobj TSRMLS_CC); + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + zend_replace_error_handling(EH_THROW, php_http_exception_runtime_class_entry, &zeh TSRMLS_CC); + php_http_message_body_add_part(obj->body, mobj->message); + zend_restore_error_handling(&zeh TSRMLS_CC); + + if (!EG(exception)) { + RETURN_ZVAL(getThis(), 1, 0); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_etag, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, etag) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + char *etag; + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + if ((etag = php_http_message_body_etag(obj->body))) { + RETURN_STRING(etag, 0); + } else { + RETURN_FALSE; + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_stat, 0, 0, 0) + ZEND_ARG_INFO(0, field) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpMessageBody, stat) +{ + char *field_str = NULL; + int field_len = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &field_str, &field_len)) { + php_http_message_body_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + const php_stream_statbuf *sb; + + PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj); + + if ((sb = php_http_message_body_stat(obj->body))) { + if (field_str && field_len) { + switch (*field_str) { + case 's': + case 'S': + RETURN_LONG(sb->sb.st_size); + break; + case 'a': + case 'A': + RETURN_LONG(sb->sb.st_atime); + break; + case 'm': + case 'M': + RETURN_LONG(sb->sb.st_mtime); + break; + case 'c': + case 'C': + RETURN_LONG(sb->sb.st_ctime); + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown stat field: '%s' (should be one of [s]ize, [a]time, [m]time or [c]time)", field_str); + break; + } + } else { + object_init(return_value); + add_property_long_ex(return_value, ZEND_STRS("size"), sb->sb.st_size TSRMLS_CC); + add_property_long_ex(return_value, ZEND_STRS("atime"), sb->sb.st_atime TSRMLS_CC); + add_property_long_ex(return_value, ZEND_STRS("mtime"), sb->sb.st_mtime TSRMLS_CC); + add_property_long_ex(return_value, ZEND_STRS("ctime"), sb->sb.st_ctime TSRMLS_CC); + } + } + } +} + +static zend_function_entry php_http_message_body_methods[] = { + PHP_ME(HttpMessageBody, __construct, ai_HttpMessageBody___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpMessageBody, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC) + PHP_MALIAS(HttpMessageBody, toString, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC) + PHP_MALIAS(HttpMessageBody, serialize, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, unserialize, ai_HttpMessageBody_unserialize, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, toStream, ai_HttpMessageBody_toStream, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, toCallback, ai_HttpMessageBody_toCallback, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, getResource, ai_HttpMessageBody_getResource, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, getBoundary, ai_HttpMessageBody_getBoundary, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, append, ai_HttpMessageBody_append, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, addForm, ai_HttpMessageBody_addForm, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, addPart, ai_HttpMessageBody_addPart, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, etag, ai_HttpMessageBody_etag, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessageBody, stat, ai_HttpMessageBody_stat, ZEND_ACC_PUBLIC) + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_message_body_class_entry; + +PHP_MINIT_FUNCTION(http_message_body) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http\\Message", "Body", php_http_message_body_methods); + php_http_message_body_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + php_http_message_body_class_entry->create_object = php_http_message_body_object_new; + memcpy(&php_http_message_body_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + php_http_message_body_object_handlers.clone_obj = php_http_message_body_object_clone; + zend_class_implements(php_http_message_body_class_entry TSRMLS_CC, 1, zend_ce_serializable); + + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_message_body.h b/php_http_message_body.h new file mode 100644 index 0000000..028ad62 --- /dev/null +++ b/php_http_message_body.h @@ -0,0 +1,78 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_MESSAGE_BODY_H +#define PHP_HTTP_MESSAGE_BODY_H + +typedef struct php_http_message_body { + int stream_id; + php_stream_statbuf ssb; + char *boundary; + unsigned refcount; +#ifdef ZTS + void ***ts; +#endif +} php_http_message_body_t; + +struct php_http_message; + +PHP_HTTP_API php_http_message_body_t *php_http_message_body_init(php_http_message_body_t **body, php_stream *stream TSRMLS_DC); +PHP_HTTP_API unsigned php_http_message_body_addref(php_http_message_body_t *body); +PHP_HTTP_API php_http_message_body_t *php_http_message_body_copy(php_http_message_body_t *from, php_http_message_body_t *to); +PHP_HTTP_API STATUS php_http_message_body_add_form(php_http_message_body_t *body, HashTable *fields, HashTable *files); +PHP_HTTP_API STATUS php_http_message_body_add_form_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len); +PHP_HTTP_API STATUS php_http_message_body_add_form_file(php_http_message_body_t *body, const char *name, const char *ctype, const char *file, php_stream *stream); +PHP_HTTP_API void php_http_message_body_add_part(php_http_message_body_t *body, struct php_http_message *part); +PHP_HTTP_API size_t php_http_message_body_append(php_http_message_body_t *body, const char *buf, size_t len); +PHP_HTTP_API size_t php_http_message_body_appendf(php_http_message_body_t *body, const char *fmt, ...); +PHP_HTTP_API void php_http_message_body_to_string(php_http_message_body_t *body, char **buf, size_t *len, off_t offset, size_t forlen); +PHP_HTTP_API STATUS php_http_message_body_to_stream(php_http_message_body_t *body, php_stream *s, off_t offset, size_t forlen); +PHP_HTTP_API STATUS php_http_message_body_to_callback(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, off_t offset, size_t forlen); +PHP_HTTP_API void php_http_message_body_free(php_http_message_body_t **body); +PHP_HTTP_API const php_stream_statbuf *php_http_message_body_stat(php_http_message_body_t *body); +#define php_http_message_body_size(b) (php_http_message_body_stat((b))->sb.st_size) +#define php_http_message_body_mtime(b) (php_http_message_body_stat((b))->sb.st_mtime) +PHP_HTTP_API char *php_http_message_body_etag(php_http_message_body_t *body); +PHP_HTTP_API const char *php_http_message_body_boundary(php_http_message_body_t *body); +PHP_HTTP_API struct php_http_message *php_http_message_body_split(php_http_message_body_t *body, const char *boundary); + +static inline php_stream *php_http_message_body_stream(php_http_message_body_t *body) +{ + TSRMLS_FETCH_FROM_CTX(body->ts); + return zend_fetch_resource(NULL TSRMLS_CC, body->stream_id, "stream", NULL, 2, php_file_le_stream(), php_file_le_pstream()); +} + +typedef struct php_http_message_body_object { + zend_object zo; + zend_object_value zv; + php_http_message_body_t *body; +} php_http_message_body_object_t; + +PHP_HTTP_API zend_class_entry *php_http_message_body_class_entry; +PHP_MINIT_FUNCTION(http_message_body); + +zend_object_value php_http_message_body_object_new(zend_class_entry *ce TSRMLS_DC); +zend_object_value php_http_message_body_object_new_ex(zend_class_entry *ce, php_http_message_body_t *body, php_http_message_body_object_t **ptr TSRMLS_DC); +zend_object_value php_http_message_body_object_clone(zval *object TSRMLS_DC); +void php_http_message_body_object_free(void *object TSRMLS_DC); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_message_object.h b/php_http_message_object.h deleted file mode 100644 index 8e28de2..0000000 --- a/php_http_message_object.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_MESSAGE_OBJECT_H -#define PHP_HTTP_MESSAGE_OBJECT_H -#ifdef ZEND_ENGINE_2 - -typedef struct _http_message_object_t { - zend_object zo; - http_message *message; - zend_object_value parent; - zval *iterator; -} http_message_object; - -extern zend_class_entry *http_message_object_ce; -extern zend_function_entry http_message_object_fe[]; - -extern PHP_MINIT_FUNCTION(http_message_object); -extern PHP_MSHUTDOWN_FUNCTION(http_message_object); - -#define http_message_object_prepend(o, p) http_message_object_prepend_ex((o), (p), 1) -#define http_message_object_prepend_ex(o, p, t) _http_message_object_prepend_ex((o), (p), (t) TSRMLS_CC) -extern void _http_message_object_prepend_ex(zval *this_ptr, zval *prepend, zend_bool top TSRMLS_DC); - -#define http_message_object_reverse(t, r) _http_message_object_reverse((t), (r) TSRMLS_CC) -extern void _http_message_object_reverse(zval *this_ptr, zval *return_value TSRMLS_DC); - -#define http_message_object_new(ce) _http_message_object_new((ce) TSRMLS_CC) -extern zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC); -#define http_message_object_new_ex(ce, msg, ptr) _http_message_object_new_ex((ce), (msg), (ptr) TSRMLS_CC) -extern zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg, http_message_object **ptr TSRMLS_DC); -#define http_message_object_clone(zobj) _http_message_object_clone_obj(zobj TSRMLS_CC) -extern zend_object_value _http_message_object_clone_obj(zval *object TSRMLS_DC); -#define http_message_object_free(o) _http_message_object_free((o) TSRMLS_CC) -extern void _http_message_object_free(zend_object *object TSRMLS_DC); - -#define HTTP_MSG_CHECK_OBJ(obj, dofail) \ - if (!(obj)->message) { \ - http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is empty"); \ - dofail; \ - } -#define HTTP_MSG_CHECK_STD() HTTP_MSG_CHECK_OBJ(obj, RETURN_FALSE) - -#define HTTP_MSG_INIT_OBJ(obj) \ - if (!(obj)->message) { \ - (obj)->message = http_message_new(); \ - } -#define HTTP_MSG_INIT_STD() HTTP_MSG_INIT_OBJ(obj) - -PHP_METHOD(HttpMessage, __construct); -PHP_METHOD(HttpMessage, getBody); -PHP_METHOD(HttpMessage, setBody); -PHP_METHOD(HttpMessage, getHeader); -PHP_METHOD(HttpMessage, getHeaders); -PHP_METHOD(HttpMessage, setHeaders); -PHP_METHOD(HttpMessage, addHeaders); -PHP_METHOD(HttpMessage, getType); -PHP_METHOD(HttpMessage, setType); -PHP_METHOD(HttpMessage, getInfo); -PHP_METHOD(HttpMessage, setInfo); -PHP_METHOD(HttpMessage, getResponseCode); -PHP_METHOD(HttpMessage, setResponseCode); -PHP_METHOD(HttpMessage, getResponseStatus); -PHP_METHOD(HttpMessage, setResponseStatus); -PHP_METHOD(HttpMessage, getRequestMethod); -PHP_METHOD(HttpMessage, setRequestMethod); -PHP_METHOD(HttpMessage, getRequestUrl); -PHP_METHOD(HttpMessage, setRequestUrl); -PHP_METHOD(HttpMessage, getHttpVersion); -PHP_METHOD(HttpMessage, setHttpVersion); -PHP_METHOD(HttpMessage, guessContentType); -PHP_METHOD(HttpMessage, getParentMessage); -PHP_METHOD(HttpMessage, send); -PHP_METHOD(HttpMessage, toString); -PHP_METHOD(HttpMessage, toMessageTypeObject); - -PHP_METHOD(HttpMessage, count); -PHP_METHOD(HttpMessage, serialize); -PHP_METHOD(HttpMessage, unserialize); -PHP_METHOD(HttpMessage, rewind); -PHP_METHOD(HttpMessage, valid); -PHP_METHOD(HttpMessage, current); -PHP_METHOD(HttpMessage, key); -PHP_METHOD(HttpMessage, next); - -PHP_METHOD(HttpMessage, factory); -PHP_METHOD(HttpMessage, fromEnv); - -PHP_METHOD(HttpMessage, detach); -PHP_METHOD(HttpMessage, prepend); -PHP_METHOD(HttpMessage, reverse); - -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_message_parser.c b/php_http_message_parser.c new file mode 100644 index 0000000..b64eb00 --- /dev/null +++ b/php_http_message_parser.c @@ -0,0 +1,522 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#ifndef DBG_PARSER +# define DBG_PARSER 0 +#endif + +typedef struct php_http_message_parser_state_spec { + php_http_message_parser_state_t state; + unsigned need_data:1; +} php_http_message_parser_state_spec_t; + +static const php_http_message_parser_state_spec_t php_http_message_parser_states[] = { + {PHP_HTTP_MESSAGE_PARSER_STATE_START, 1}, + {PHP_HTTP_MESSAGE_PARSER_STATE_HEADER, 1}, + {PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE, 0}, + {PHP_HTTP_MESSAGE_PARSER_STATE_BODY, 0}, + {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB, 1}, + {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, 1}, + {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, 1}, + {PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, 0}, + {PHP_HTTP_MESSAGE_PARSER_STATE_DONE, 0} +}; + +#if DBG_PARSER +const char *php_http_message_parser_state_name(php_http_message_parser_state_t state) { + const char *states[] = {"START", "HEADER", "HEADER_DONE", "BODY", "BODY_DUMB", "BODY_LENGTH", "BODY_CHUNK", "BODY_DONE", "DONE"}; + + if (state < 0 || state > (sizeof(states)/sizeof(char*))-1) { + return "FAILURE"; + } + return states[state]; +} +#endif + +php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser TSRMLS_DC) +{ + if (!parser) { + parser = emalloc(sizeof(*parser)); + } + memset(parser, 0, sizeof(*parser)); + + TSRMLS_SET_CTX(parser->ts); + + php_http_header_parser_init(&parser->header TSRMLS_CC); + zend_stack_init(&parser->stack); + + return parser; +} + +php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...) +{ + php_http_message_parser_state_t state; + va_list va_args; + unsigned i; + + va_start(va_args, argc); + for (i = 0; i < argc; ++i) { + state = va_arg(va_args, php_http_message_parser_state_t); + zend_stack_push(&parser->stack, &state, sizeof(state)); + } + va_end(va_args); + + return state; +} + +php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser) +{ + php_http_message_parser_state_t *state; + + if (SUCCESS == zend_stack_top(&parser->stack, (void *) &state)) { + return *state; + } + return PHP_HTTP_MESSAGE_PARSER_STATE_START; +} + +php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_message_parser_t *parser) +{ + php_http_message_parser_state_t state, *state_ptr; + if (SUCCESS == zend_stack_top(&parser->stack, (void *) &state_ptr)) { + state = *state_ptr; + zend_stack_del_top(&parser->stack); + return state; + } + return PHP_HTTP_MESSAGE_PARSER_STATE_START; +} + +void php_http_message_parser_dtor(php_http_message_parser_t *parser) +{ + php_http_header_parser_dtor(&parser->header); + zend_stack_destroy(&parser->stack); + if (parser->dechunk) { + php_http_encoding_stream_free(&parser->dechunk); + } + if (parser->inflate) { + php_http_encoding_stream_free(&parser->inflate); + } +} + +void php_http_message_parser_free(php_http_message_parser_t **parser) +{ + if (*parser) { + php_http_message_parser_dtor(*parser); + efree(*parser); + *parser = NULL; + } +} + +php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_message_parser_t *parser, php_stream *s, unsigned flags, php_http_message_t **message) +{ + php_http_buffer_t buf; + php_http_message_parser_state_t state = PHP_HTTP_MESSAGE_PARSER_STATE_START; + TSRMLS_FETCH_FROM_CTX(parser->ts); + + php_http_buffer_init_ex(&buf, 0x1000, PHP_HTTP_BUFFER_INIT_PREALLOC); + + while (!php_stream_eof(s)) { + size_t len = 0; +#if DBG_PARSER + fprintf(stderr, "#SP: %s (f:%u)\n", php_http_message_parser_state_name(state), flags); +#endif + switch (state) { + case PHP_HTTP_MESSAGE_PARSER_STATE_START: + case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER: + case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE: + /* read line */ + php_stream_get_line(s, buf.data + buf.used, buf.free, &len); + php_http_buffer_account(&buf, len); + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB: + /* read all */ + php_http_buffer_account(&buf, php_stream_read(s, buf.data + buf.used, buf.free)); + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH: + /* read body_length */ + php_http_buffer_account(&buf, php_stream_read(s, buf.data + buf.used, MIN(buf.free, parser->body_length))); + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED: + /* duh, this is very naive */ + if (len) { + size_t read = php_stream_read(s, buf.data + buf.used, MIN(len, buf.free)); + + php_http_buffer_account(&buf, read); + + len -= read; + } else { + php_http_buffer_resize(&buf, 24); + php_stream_get_line(s, buf.data, buf.free, &len); + php_http_buffer_account(&buf, len); + + len = strtoul(buf.data + buf.used - len, NULL, 16); + } + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY: + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE: + /* should not occur */ + abort(); + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_DONE: + case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE: + php_http_buffer_dtor(&buf); + return php_http_message_parser_state_is(parser); + } + + state = php_http_message_parser_parse(parser, &buf, flags, message); + } + + php_http_buffer_dtor(&buf); + return PHP_HTTP_MESSAGE_PARSER_STATE_DONE; +} + + +php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, php_http_message_t **message) +{ + char *str = NULL; + size_t len = 0; + size_t cut = 0; + TSRMLS_FETCH_FROM_CTX(parser->ts); + + while (buffer->used || !php_http_message_parser_states[php_http_message_parser_state_is(parser)].need_data) { +#if DBG_PARSER + fprintf(stderr, "#MP: %s (f: %u, t:%d, l:%zu)\n", + php_http_message_parser_state_name(php_http_message_parser_state_is(parser)), + flags, + message && *message ? (*message)->type : -1, + buffer->used + ); + _dpf(0, buffer->data, buffer->used); +#endif + + switch (php_http_message_parser_state_pop(parser)) + { + case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE: + return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); + + case PHP_HTTP_MESSAGE_PARSER_STATE_START: + { + char *ptr = buffer->data; + + while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) { + ++ptr; + } + + php_http_buffer_cut(buffer, 0, ptr - buffer->data); + + if (buffer->used) { + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER); + } + break; + } + + case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER: + { + unsigned header_parser_flags = (flags & PHP_HTTP_MESSAGE_PARSER_CLEANUP) ? PHP_HTTP_HEADER_PARSER_CLEANUP : 0; + + switch (php_http_header_parser_parse(&parser->header, buffer, header_parser_flags, *message ? &(*message)->hdrs : NULL, (php_http_info_callback_t) php_http_message_info_callback, message)) { + case PHP_HTTP_HEADER_PARSER_STATE_FAILURE: + return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE; + + case PHP_HTTP_HEADER_PARSER_STATE_DONE: + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE); + break; + + default: + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER); + if (buffer->used) { + return PHP_HTTP_MESSAGE_PARSER_STATE_HEADER; + } + } + break; + } + + case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE: + { + zval *h, *h_loc = NULL, *h_con = NULL, **h_cl = NULL, **h_cr = NULL, **h_te = NULL; + + if ((h = php_http_message_header(*message, ZEND_STRL("Transfer-Encoding"), 1))) { + zend_hash_update(&(*message)->hdrs, "X-Original-Transfer-Encoding", sizeof("X-Original-Transfer-Encoding"), &h, sizeof(zval *), (void *) &h_te); + zend_hash_del(&(*message)->hdrs, "Transfer-Encoding", sizeof("Transfer-Encoding")); + } + if ((h = php_http_message_header(*message, ZEND_STRL("Content-Length"), 1))) { + zend_hash_update(&(*message)->hdrs, "X-Original-Content-Length", sizeof("X-Original-Content-Length"), &h, sizeof(zval *), (void *) &h_cl); + } + if ((h = php_http_message_header(*message, ZEND_STRL("Content-Range"), 1))) { + zend_hash_update(&(*message)->hdrs, "X-Original-Content-Range", sizeof("X-Original-Content-Range"), &h, sizeof(zval *), (void *) &h_cr); + zend_hash_del(&(*message)->hdrs, "Content-Range", sizeof("Content-Range")); + } + + /* default */ + MAKE_STD_ZVAL(h); + ZVAL_LONG(h, 0); + zend_hash_update(&(*message)->hdrs, "Content-Length", sizeof("Content-Length"), &h, sizeof(zval *), NULL); + + /* so, if curl sees a 3xx code, a Location header and a Connection:close header + * it decides not to read the response body. + */ + if ((flags & PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS) + && (*message)->type == PHP_HTTP_RESPONSE + && (*message)->http.info.response.code/100 == 3 + && (h_loc = php_http_message_header(*message, ZEND_STRL("Location"), 1)) + && (h_con = php_http_message_header(*message, ZEND_STRL("Connection"), 1)) + ) { + if (php_http_match(Z_STRVAL_P(h_con), "close", PHP_HTTP_MATCH_WORD)) { + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); + zval_ptr_dtor(&h_loc); + zval_ptr_dtor(&h_con); + break; + } + } + if (h_loc) { + zval_ptr_dtor(&h_loc); + } + if (h_con) { + zval_ptr_dtor(&h_con); + } + + if ((h = php_http_message_header(*message, ZEND_STRL("Content-Encoding"), 1))) { + if (php_http_match(Z_STRVAL_P(h), "gzip", PHP_HTTP_MATCH_WORD) + || php_http_match(Z_STRVAL_P(h), "x-gzip", PHP_HTTP_MATCH_WORD) + || php_http_match(Z_STRVAL_P(h), "deflate", PHP_HTTP_MATCH_WORD) + ) { + if (parser->inflate) { + php_http_encoding_stream_reset(&parser->inflate); + } else { + parser->inflate = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_inflate_ops(), 0 TSRMLS_CC); + } + zend_hash_update(&(*message)->hdrs, "X-Original-Content-Encoding", sizeof("X-Original-Content-Encoding"), &h, sizeof(zval *), NULL); + zend_hash_del(&(*message)->hdrs, "Content-Encoding", sizeof("Content-Encoding")); + } else { + zval_ptr_dtor(&h); + } + } + + if ((flags & PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES)) { + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB); + } else { + if (h_te) { + if (strstr(Z_STRVAL_PP(h_te), "chunked")) { + parser->dechunk = php_http_encoding_stream_init(parser->dechunk, php_http_encoding_stream_get_dechunk_ops(), 0 TSRMLS_CC); + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED); + break; + } + } + + if (h_cl) { + char *stop; + + if (Z_TYPE_PP(h_cl) == IS_STRING) { + parser->body_length = strtoul(Z_STRVAL_PP(h_cl), &stop, 10); + + if (stop != Z_STRVAL_PP(h_cl)) { + php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + break; + } + } else if (Z_TYPE_PP(h_cl) == IS_LONG) { + parser->body_length = Z_LVAL_PP(h_cl); + php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + break; + } + } + + if (h_cr) { + ulong total = 0, start = 0, end = 0; + + if (!strncasecmp(Z_STRVAL_PP(h_cr), "bytes", lenof("bytes")) + && ( Z_STRVAL_P(h)[lenof("bytes")] == ':' + || Z_STRVAL_P(h)[lenof("bytes")] == ' ' + || Z_STRVAL_P(h)[lenof("bytes")] == '=' + ) + ) { + char *total_at = NULL, *end_at = NULL; + char *start_at = Z_STRVAL_PP(h_cr) + sizeof("bytes"); + + start = strtoul(start_at, &end_at, 10); + if (end_at) { + end = strtoul(end_at + 1, &total_at, 10); + if (total_at && strncmp(total_at + 1, "*", 1)) { + total = strtoul(total_at + 1, NULL, 10); + } + + if (end >= start && (!total || end < total)) { + parser->body_length = end + 1 - start; + php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + break; + } + } + } + } + + + if ((*message)->type == PHP_HTTP_REQUEST) { + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); + } else { + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB); + } + } + break; + } + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY: + { + if (len) { + zval *zcl; + + if (parser->inflate) { + char *dec_str = NULL; + size_t dec_len; + + if (SUCCESS != php_http_encoding_stream_update(parser->inflate, str, len, &dec_str, &dec_len)) { + return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); + } + + if (str != buffer->data) { + STR_FREE(str); + } + str = dec_str; + len = dec_len; + } + + php_stream_write(php_http_message_body_stream((*message)->body), str, len); + + /* keep track */ + MAKE_STD_ZVAL(zcl); + ZVAL_LONG(zcl, php_http_message_body_size((*message)->body)); + zend_hash_update(&(*message)->hdrs, "Content-Length", sizeof("Content-Length"), &zcl, sizeof(zval *), NULL); + } + + if (cut) { + php_http_buffer_cut(buffer, 0, cut); + } + + if (str != buffer->data) { + STR_FREE(str); + } + + str = NULL; + len = 0; + cut = 0; + break; + } + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB: + { + str = buffer->data; + len = buffer->used; + cut = len; + + php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + break; + } + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH: + { + len = MIN(parser->body_length, buffer->used); + str = buffer->data; + cut = len; + + parser->body_length -= len; + + php_http_message_parser_state_push(parser, 2, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + break; + } + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED: + { + /* + * - pass available data through the dechunk stream + * - pass decoded data along + * - if stream zeroed: + * Y: - cut processed string out of buffer, but leave length of unprocessed dechunk stream data untouched + * - body done + * N: - parse ahaed + */ + char *dec_str = NULL; + size_t dec_len; + + if (SUCCESS != php_http_encoding_stream_update(parser->dechunk, buffer->data, buffer->used, &dec_str, &dec_len)) { + return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE; + } + + str = dec_str; + len = dec_len; + + if (php_http_encoding_stream_done(parser->dechunk)) { + cut = buffer->used - PHP_HTTP_BUFFER(parser->dechunk->ctx)->used; + php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + } else { + cut = buffer->used; + php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + } + break; + } + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE: + { + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE); + + if (parser->dechunk) { + char *dec_str = NULL; + size_t dec_len; + + if (SUCCESS != php_http_encoding_stream_finish(parser->dechunk, &dec_str, &dec_len)) { + return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE); + } + php_http_encoding_stream_dtor(parser->dechunk); + + if (dec_str && dec_len) { + str = dec_str; + len = dec_len; + cut = 0; + php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + } + } + + break; + } + + case PHP_HTTP_MESSAGE_PARSER_STATE_DONE: { + char *ptr = buffer->data; + + while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) { + ++ptr; + } + + php_http_buffer_cut(buffer, 0, ptr - buffer->data); + + if (!(flags & PHP_HTTP_MESSAGE_PARSER_GREEDY)) { + return PHP_HTTP_MESSAGE_PARSER_STATE_DONE; + } + break; + } + } + } + + return php_http_message_parser_state_is(parser); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_message_parser.h b/php_http_message_parser.h new file mode 100644 index 0000000..8ecf991 --- /dev/null +++ b/php_http_message_parser.h @@ -0,0 +1,69 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_MESSAGE_PARSER_H +#define PHP_HTTP_MESSAGE_PARSER_H + +#include "php_http_header_parser.h" +#include "php_http_encoding.h" +#include "php_http_message.h" + +typedef enum php_http_message_parser_state { + PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE = FAILURE, + PHP_HTTP_MESSAGE_PARSER_STATE_START = 0, + PHP_HTTP_MESSAGE_PARSER_STATE_HEADER, + PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE, + PHP_HTTP_MESSAGE_PARSER_STATE_BODY, + PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB, + PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, + PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, + PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, + PHP_HTTP_MESSAGE_PARSER_STATE_DONE +} php_http_message_parser_state_t; + +#define PHP_HTTP_MESSAGE_PARSER_CLEANUP 0x1 +#define PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES 0x2 +#define PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS 0x4 +#define PHP_HTTP_MESSAGE_PARSER_GREEDY 0x8 + +typedef struct php_http_message_parser { + php_http_header_parser_t header; + zend_stack stack; + size_t body_length; + php_http_message_t *message; + php_http_encoding_stream_t *dechunk; + php_http_encoding_stream_t *inflate; +#ifdef ZTS + void ***ts; +#endif +} php_http_message_parser_t; + +PHP_HTTP_API php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser TSRMLS_DC); +PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...); +PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser); +PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_message_parser_t *parser); +PHP_HTTP_API void php_http_message_parser_dtor(php_http_message_parser_t *parser); +PHP_HTTP_API void php_http_message_parser_free(php_http_message_parser_t **parser); +PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, php_http_message_t **message); +PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_message_parser_t *parser, php_stream *s, unsigned flags, php_http_message_t **message); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_misc.c b/php_http_misc.c new file mode 100644 index 0000000..0ba19f9 --- /dev/null +++ b/php_http_misc.c @@ -0,0 +1,258 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#include +#include + +/* SLEEP */ + +void php_http_sleep(double s) +{ +#if defined(PHP_WIN32) + Sleep((DWORD) PHP_HTTP_MSEC(s)); +#elif defined(HAVE_USLEEP) + usleep(PHP_HTTP_USEC(s)); +#elif defined(HAVE_NANOSLEEP) + struct timespec req, rem; + + req.tv_sec = (time_t) s; + req.tv_nsec = PHP_HTTP_NSEC(s) % PHP_HTTP_NANOSEC; + + while (nanosleep(&req, &rem) && (errno == EINTR) && (PHP_HTTP_NSEC(rem.tv_sec) + rem.tv_nsec) > PHP_HTTP_NSEC(PHP_HTTP_DIFFSEC))) { + req.tv_sec = rem.tv_sec; + req.tv_nsec = rem.tv_nsec; + } +#else + struct timeval timeout; + + timeout.tv_sec = (time_t) s; + timeout.tv_usec = PHP_HTTP_USEC(s) % PHP_HTTP_MCROSEC; + + select(0, NULL, NULL, NULL, &timeout); +#endif +} + + +/* STRING UTILITIES */ + +int php_http_match(const char *haystack_str, const char *needle_str, int flags) +{ + int result = 0; + + if (!haystack_str || !needle_str) { + return result; + } + + if (flags & PHP_HTTP_MATCH_FULL) { + if (flags & PHP_HTTP_MATCH_CASE) { + result = !strcmp(haystack_str, needle_str); + } else { + result = !strcasecmp(haystack_str, needle_str); + } + } else { + char *found, *haystack = estrdup(haystack_str), *needle = estrdup(needle_str); + + if (flags & PHP_HTTP_MATCH_CASE) { + found = zend_memnstr(haystack, needle, strlen(needle), haystack+strlen(haystack)); + } else { + found = php_stristr(haystack, needle, strlen(haystack), strlen(needle)); + } + + if (found) { + if (!(flags & PHP_HTTP_MATCH_WORD) + || ( (found == haystack || !PHP_HTTP_IS_CTYPE(alnum, *(found - 1))) + && (!*(found + strlen(needle)) || !PHP_HTTP_IS_CTYPE(alnum, *(found + strlen(needle)))) + ) + ) { + result = 1; + } + } + + STR_FREE(haystack); + STR_FREE(needle); + } + + return result; +} + +char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen) +{ + size_t i; + int wasalpha; + + if (key && key_len) { + if ((wasalpha = PHP_HTTP_IS_CTYPE(alpha, key[0]))) { + key[0] = (char) (uctitle ? PHP_HTTP_TO_CTYPE(upper, key[0]) : PHP_HTTP_TO_CTYPE(lower, key[0])); + } + for (i = 1; i < key_len; i++) { + if (PHP_HTTP_IS_CTYPE(alpha, key[i])) { + key[i] = (char) (((!wasalpha) && uctitle) ? PHP_HTTP_TO_CTYPE(upper, key[i]) : PHP_HTTP_TO_CTYPE(lower, key[i])); + wasalpha = 1; + } else { + if (xhyphen && (key[i] == '_')) { + key[i] = '-'; + } + wasalpha = 0; + } + } + } + return key; +} + + +size_t php_http_boundary(char *buf, size_t buf_len TSRMLS_DC) +{ + return snprintf(buf, buf_len, "%15.15F", PHP_HTTP_G->env.request.time * php_combined_lcg(TSRMLS_C)); +} + +int php_http_select_str(const char *cmp, int argc, ...) +{ + va_list argv; + int match = -1; + + if (cmp && argc > 0) { + int i; + + va_start(argv, argc); + for (i = 0; i < argc; ++i) { + const char *test = va_arg(argv, const char *); + + if (!strcasecmp(cmp, test)) { + match = i; + break; + } + } + va_end(argv); + } + + return match; +} + + +/* ARRAYS */ + +unsigned php_http_array_list(HashTable *ht TSRMLS_DC, unsigned argc, ...) +{ + HashPosition pos; + unsigned argl = 0; + va_list argv; + + va_start(argv, argc); + for ( zend_hash_internal_pointer_reset_ex(ht, &pos); + SUCCESS == zend_hash_has_more_elements_ex(ht, &pos) && (argl < argc); + zend_hash_move_forward_ex(ht, &pos)) + { + zval **data, ***argp = (zval ***) va_arg(argv, zval ***); + + if (SUCCESS == zend_hash_get_current_data_ex(ht, (void *) &data, &pos)) { + *argp = data; + ++argl; + } + } + va_end(argv); + + return argl; +} + +int php_http_array_apply_append_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +{ + int flags; + char *key = NULL; + HashTable *dst; + zval **data = NULL, **value = (zval **) pDest; + + dst = va_arg(args, HashTable *); + flags = va_arg(args, int); + + if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) { + if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) { + key = php_http_pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1); + zend_hash_find(dst, key, hash_key->nKeyLength, (void *) &data); + } else { + zend_hash_quick_find(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &data); + } + + Z_ADDREF_P(*value); + if (data) { + if (Z_TYPE_PP(data) != IS_ARRAY) { + convert_to_array(*data); + } + add_next_index_zval(*data, *value); + } else if (key) { + zend_symtable_update(dst, key, hash_key->nKeyLength, value, sizeof(zval *), NULL); + } else { + zend_hash_quick_add(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, value, sizeof(zval *), NULL); + } + + if (key) { + efree(key); + } + } + + return ZEND_HASH_APPLY_KEEP; +} + +int php_http_array_apply_merge_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +{ + int flags; + char *key = NULL; + HashTable *dst; + zval **value = (zval **) pDest; + + dst = va_arg(args, HashTable *); + flags = va_arg(args, int); + + if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) { + Z_ADDREF_P(*value); + if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) { + key = php_http_pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1); + zend_hash_update(dst, key, hash_key->nKeyLength, (void *) value, sizeof(zval *), NULL); + efree(key); + } else { + zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) value, sizeof(zval *), NULL); + } + } + + return ZEND_HASH_APPLY_KEEP; +} + +/* PASS CALLBACK */ + +size_t php_http_pass_fcall_callback(void *cb_arg, const char *str, size_t len) +{ + php_http_pass_fcall_arg_t *fcd = cb_arg; + zval *zdata; + TSRMLS_FETCH_FROM_CTX(fcd->ts); + + MAKE_STD_ZVAL(zdata); + ZVAL_STRINGL(zdata, str, len, 1); + if (SUCCESS == zend_fcall_info_argn(&fcd->fci TSRMLS_CC, 2, &fcd->fcz, &zdata)) { + zend_fcall_info_call(&fcd->fci, &fcd->fcc, NULL, NULL TSRMLS_CC); + zend_fcall_info_args_clear(&fcd->fci, 0); + } + zval_ptr_dtor(&zdata); + return len; +} + + +/* ZEND */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_misc.h b/php_http_misc.h new file mode 100644 index 0000000..17cfec7 --- /dev/null +++ b/php_http_misc.h @@ -0,0 +1,321 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_MISC_H +#define PHP_HTTP_MISC_H + +/* DEFAULTS */ + +/* DATE FORMAT RFC1123 */ +#define PHP_HTTP_DATE_FORMAT "D, d M Y H:i:s \\G\\M\\T" + +/* CR LF */ +#define PHP_HTTP_CRLF "\r\n" + +/* def URL arg separator */ +#define PHP_HTTP_URL_ARGSEP "&" + +/* send buffer size */ +#define PHP_HTTP_SENDBUF_SIZE 40960 + +/* SLEEP */ + +#define PHP_HTTP_DIFFSEC (0.001) +#define PHP_HTTP_MLLISEC (1000) +#define PHP_HTTP_MCROSEC (1000 * 1000) +#define PHP_HTTP_NANOSEC (1000 * 1000 * 1000) +#define PHP_HTTP_MSEC(s) ((long)(s * PHP_HTTP_MLLISEC)) +#define PHP_HTTP_USEC(s) ((long)(s * PHP_HTTP_MCROSEC)) +#define PHP_HTTP_NSEC(s) ((long)(s * PHP_HTTP_NANOSEC)) + +PHP_HTTP_API void php_http_sleep(double s); + +/* STRING UTILITIES */ + +#ifndef STR_SET +# define STR_SET(STR, SET) \ + { \ + STR_FREE(STR); \ + STR = SET; \ + } +#endif + +#define STR_PTR(s) (s?s:"") + +#define lenof(S) (sizeof(S) - 1) + +#define PHP_HTTP_MATCH_LOOSE 0 +#define PHP_HTTP_MATCH_CASE 0x01 +#define PHP_HTTP_MATCH_WORD 0x10 +#define PHP_HTTP_MATCH_FULL 0x20 +#define PHP_HTTP_MATCH_STRICT (PHP_HTTP_MATCH_CASE|PHP_HTTP_MATCH_FULL) + +int php_http_match(const char *haystack, const char *needle, int flags); +char *php_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen); +size_t php_http_boundary(char *buf, size_t len TSRMLS_DC); +int php_http_select_str(const char *cmp, int argc, ...); + +static inline const char *php_http_locate_str(const char *h, size_t h_len, const char *n, size_t n_len) +{ + const char *p, *e; + + if (n_len && h_len) { + e = h + h_len; + do { + if (*h == *n) { + for (p = n; *p == h[p-n]; ++p) { + if (p == n+n_len-1) { + return h; + } + } + } + } while (h++ != e); + } + + return NULL; +} + +static inline const char *php_http_locate_eol(const char *line, int *eol_len) +{ + const char *eol = strpbrk(line, "\r\n"); + + if (eol_len) { + *eol_len = eol ? ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1) : 0; + } + return eol; +} + +static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, int *eol_len) +{ + const char *eol; + + for (eol = bin; eol - bin < len; ++eol) { + if (*eol == '\r' || *eol == '\n') { + if (eol_len) { + *eol_len = ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1); + } + return eol; + } + } + + return NULL; +} + +/* ZEND */ + +#if PHP_VERSION_ID < 50400 +# define object_properties_init(o, ce) zend_hash_copy(((zend_object *) o)->properties, &(ce->default_properties), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)) +# define PHP_HTTP_ZEND_LITERAL_DC +# define PHP_HTTP_ZEND_LITERAL_CC +# define PHP_HTTP_ZEND_LITERAL_CCN +# define ZVAL_COPY_VALUE(zv, arr) do { \ + (zv)->value = (arr)->value; \ + Z_TYPE_P(zv) = Z_TYPE_P(arr); \ + } while (0) +#else +# define PHP_HTTP_ZEND_LITERAL_DC , const zend_literal *literal_key +# define PHP_HTTP_ZEND_LITERAL_CC , (literal_key) +# define PHP_HTTP_ZEND_LITERAL_CCN , NULL +#endif + +#define INIT_PZVAL_ARRAY(zv, ht) \ + { \ + INIT_PZVAL((zv)); \ + Z_TYPE_P(zv) = IS_ARRAY; \ + Z_ARRVAL_P(zv) = (ht); \ + } + +static inline zval *php_http_ztyp(int type, zval *z) +{ + SEPARATE_ARG_IF_REF(z); + if (Z_TYPE_P(z) != type) { + switch (type) { + case IS_NULL: convert_to_null_ex(&z); break; + case IS_BOOL: convert_to_boolean_ex(&z); break; + case IS_LONG: convert_to_long_ex(&z); break; + case IS_DOUBLE: convert_to_double_ex(&z); break; + case IS_STRING: convert_to_string_ex(&z); break; + case IS_ARRAY: convert_to_array_ex(&z); break; + case IS_OBJECT: convert_to_object_ex(&z); break; + } + } + return z; +} + +static inline zval *php_http_zsep(zend_bool add_ref, int type, zval *z) +{ + if (add_ref) { + Z_ADDREF_P(z); + } + if (Z_TYPE_P(z) != type) { + switch (type) { + case IS_NULL: convert_to_null_ex(&z); break; + case IS_BOOL: convert_to_boolean_ex(&z); break; + case IS_LONG: convert_to_long_ex(&z); break; + case IS_DOUBLE: convert_to_double_ex(&z); break; + case IS_STRING: convert_to_string_ex(&z); break; + case IS_ARRAY: convert_to_array_ex(&z); break; + case IS_OBJECT: convert_to_object_ex(&z); break; + } + } else { + SEPARATE_ZVAL_IF_NOT_REF(&z); + } + return z; +} + +static inline STATUS php_http_ini_entry(const char *name_str, size_t name_len, const char **value_str, size_t *value_len, zend_bool orig TSRMLS_DC) +{ + zend_ini_entry *ini_entry; + + if (SUCCESS == zend_hash_find(EG(ini_directives), name_str, name_len + 1, (void *) &ini_entry)) { + if (orig && ini_entry->modified) { + *value_str = ini_entry->orig_value; + *value_len = (size_t) ini_entry->orig_value_length; + } else { + *value_str = ini_entry->value; + *value_len = (size_t) ini_entry->value_length; + } + return SUCCESS; + } + return FAILURE; +} + +/* return object(values) */ +#define RETVAL_OBJECT(o, addref) \ + RETVAL_OBJVAL((o)->value.obj, addref) +#define RETURN_OBJECT(o, addref) \ + RETVAL_OBJECT(o, addref); \ + return +#define RETVAL_OBJVAL(ov, addref) \ + ZVAL_OBJVAL(return_value, ov, addref) +#define RETURN_OBJVAL(ov, addref) \ + RETVAL_OBJVAL(ov, addref); \ + return +#define ZVAL_OBJVAL(zv, ov, addref) \ + (zv)->type = IS_OBJECT; \ + (zv)->value.obj = (ov);\ + if (addref && Z_OBJ_HT_P(zv)->add_ref) { \ + Z_OBJ_HT_P(zv)->add_ref((zv) TSRMLS_CC); \ + } + +#define Z_OBJ_DELREF(z) \ + if (Z_OBJ_HT(z)->del_ref) { \ + Z_OBJ_HT(z)->del_ref(&(z) TSRMLS_CC); \ + } +#define Z_OBJ_ADDREF(z) \ + if (Z_OBJ_HT(z)->add_ref) { \ + Z_OBJ_HT(z)->add_ref(&(z) TSRMLS_CC); \ + } +#define Z_OBJ_DELREF_P(z) \ + if (Z_OBJ_HT_P(z)->del_ref) { \ + Z_OBJ_HT_P(z)->del_ref((z) TSRMLS_CC); \ + } +#define Z_OBJ_ADDREF_P(z) \ + if (Z_OBJ_HT_P(z)->add_ref) { \ + Z_OBJ_HT_P(z)->add_ref((z) TSRMLS_CC); \ + } +#define Z_OBJ_DELREF_PP(z) \ + if (Z_OBJ_HT_PP(z)->del_ref) { \ + Z_OBJ_HT_PP(z)->del_ref(*(z) TSRMLS_CC); \ + } +#define Z_OBJ_ADDREF_PP(z) \ + if (Z_OBJ_HT_PP(z)->add_ref) { \ + Z_OBJ_HT_PP(z)->add_ref(*(z) TSRMLS_CC); \ + } + +#define EMPTY_FUNCTION_ENTRY {NULL, NULL, NULL, 0, 0} + +#define PHP_MINIT_CALL(func) PHP_MINIT(func)(INIT_FUNC_ARGS_PASSTHRU) +#define PHP_RINIT_CALL(func) PHP_RINIT(func)(INIT_FUNC_ARGS_PASSTHRU) +#define PHP_MSHUTDOWN_CALL(func) PHP_MSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU) +#define PHP_RSHUTDOWN_CALL(func) PHP_RSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU) + +/* ARRAYS */ +PHP_HTTP_API unsigned php_http_array_list(HashTable *ht TSRMLS_DC, unsigned argc, ...); + +typedef struct php_http_array_hashkey { + char *str; + uint len; + ulong num; + uint dup:1; + uint type:31; +} php_http_array_hashkey_t; +#define php_http_array_hashkey_init(dup) {NULL, 0, 0, (dup), 0} + +static inline void php_http_array_hashkey_stringify(php_http_array_hashkey_t *key) +{ + if (key->type != HASH_KEY_IS_STRING) { + key->len = spprintf(&key->str, 0, "%lu", key->num) + 1; + } +} + +static inline void php_http_array_hashkey_stringfree(php_http_array_hashkey_t *key) +{ + if (key->type != HASH_KEY_IS_STRING || key->dup) { + STR_FREE(key->str); + } +} + +#define FOREACH_VAL(pos, array, val) FOREACH_HASH_VAL(pos, HASH_OF(array), val) +#define FOREACH_HASH_VAL(pos, hash, val) \ + for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ + zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \ + zend_hash_move_forward_ex(hash, &pos)) + +#define FOREACH_KEY(pos, array, key) FOREACH_HASH_KEY(pos, HASH_OF(array), key) +#define FOREACH_HASH_KEY(pos, hash, _key) \ + for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ + ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (zend_bool) (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT; \ + zend_hash_move_forward_ex(hash, &pos)) \ + +#define FOREACH_KEYVAL(pos, array, key, val) FOREACH_HASH_KEYVAL(pos, HASH_OF(array), key, val) +#define FOREACH_HASH_KEYVAL(pos, hash, _key, val) \ + for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ + ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (zend_bool) (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT && \ + zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \ + zend_hash_move_forward_ex(hash, &pos)) + +#define array_copy(src, dst) zend_hash_copy(dst, src, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)) +#define ARRAY_JOIN_STRONLY 1 +#define ARRAY_JOIN_PRETTIFY 2 +#define array_join(src, dst, append, flags) zend_hash_apply_with_arguments(src TSRMLS_CC, (append)?php_http_array_apply_append_func:php_http_array_apply_merge_func, 2, dst, (int)flags) + +int php_http_array_apply_append_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key); +int php_http_array_apply_merge_func(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key); + +/* PASS CALLBACK */ + +typedef size_t (*php_http_pass_callback_t)(void *cb_arg, const char *str, size_t len); +typedef size_t (*php_http_pass_php_http_buffer_callback_t)(void *cb_arg, php_http_buffer_t *str); +typedef size_t (*php_http_pass_format_callback_t)(void *cb_arg, const char *fmt, ...); + +typedef struct php_http_pass_fcall_arg { + zval *fcz; + zend_fcall_info fci; + zend_fcall_info_cache fcc; +#ifdef ZTS + void ***ts; +#endif +} php_http_pass_fcall_arg_t; + +PHP_HTTP_API size_t php_http_pass_fcall_callback(void *cb_arg, const char *str, size_t len); + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_negotiate.c b/php_http_negotiate.c new file mode 100644 index 0000000..ae10ddf --- /dev/null +++ b/php_http_negotiate.c @@ -0,0 +1,173 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +static int php_http_negotiate_sort(const void *a, const void *b TSRMLS_DC) +{ + zval result, *first, *second; + + first = *((zval **) (*((Bucket **) a))->pData); + second= *((zval **) (*((Bucket **) b))->pData); + + if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) { + return 0; + } + return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0)); +} + +#define M_PRI 5 +#define M_SEC 2 +#define M_ANY 1 +#define M_NOT 0 +#define M_ALL -1 +static inline unsigned php_http_negotiate_match(const char *param_str, size_t param_len, const char *supported_str, size_t supported_len, const char *sep_str, size_t sep_len) +{ + int match = M_NOT; + + if (param_len == supported_len && !strncasecmp(param_str, supported_str, param_len)) { + /* that was easy */ + match = M_ALL; + } else if (sep_str && sep_len) { + const char *param_sec = php_http_locate_str(param_str, param_len, sep_str, sep_len); + size_t param_pri_len = param_sec ? param_sec - param_str : param_len; + const char *supported_sec = php_http_locate_str(supported_str, supported_len, sep_str, sep_len); + size_t supported_pri_len = supported_sec ? supported_sec - supported_str : supported_len; + size_t cmp_len = MIN(param_pri_len, supported_pri_len); + + if (((*param_str == '*') || (*supported_str == '*')) + || ((param_pri_len == supported_pri_len) && !strncasecmp(param_str, supported_str, param_pri_len)) + || ((!param_sec || !supported_sec) && cmp_len && !strncasecmp(param_str, supported_str, cmp_len)) + ) { + match += M_PRI; + } + + if (param_sec && supported_sec && !strcasecmp(param_sec, supported_sec)) { + match += M_SEC; + } + + if ((param_sec && *(param_sec + sep_len) == '*') + || (supported_sec && *(supported_sec + sep_len) == '*') + || ((*param_str == '*') || (*supported_str == '*')) + ) { + match += M_ANY; + } + } +#if 0 + fprintf(stderr, "match: %s == %s => %u\n", supported_str, param_str, match); +#endif + return match; +} + +static int php_http_negotiate_reduce(void *p TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +{ + unsigned best_match = 0; + HashPosition pos; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + zval **q = NULL, **val, *supported = php_http_ztyp(IS_STRING, *(zval **)p); + HashTable *params = va_arg(args, HashTable *); + HashTable *result = va_arg(args, HashTable *); + const char *sep_str = va_arg(args, const char *); + size_t sep_len = va_arg(args, size_t); + + FOREACH_HASH_KEYVAL(pos, params, key, val) { + if (key.type == HASH_KEY_IS_STRING) { + unsigned match = php_http_negotiate_match(key.str, key.len-1, Z_STRVAL_P(supported), Z_STRLEN_P(supported), sep_str, sep_len); + + if (match > best_match) { + best_match = match; + q = val; + } + } + } + + if (q && Z_DVAL_PP(q) > 0) { + Z_ADDREF_PP(q); + zend_hash_update(result, Z_STRVAL_P(supported), Z_STRLEN_P(supported) + 1, (void *) q, sizeof(zval *), NULL); + } + + zval_ptr_dtor(&supported); + return ZEND_HASH_APPLY_KEEP; +} + +HashTable *php_http_negotiate(const char *value_str, size_t value_len, HashTable *supported, const char *primary_sep_str, size_t primary_sep_len TSRMLS_DC) +{ + HashTable *result = NULL; + + if (value_str && value_len) { + unsigned i = 0; + zval arr, **val, **arg, **zq; + HashPosition pos; + HashTable params; + php_http_array_hashkey_t key = php_http_array_hashkey_init(1); + php_http_params_opts_t opts; + + zend_hash_init(¶ms, 10, NULL, ZVAL_PTR_DTOR, 0); + php_http_params_opts_default_get(&opts); + opts.input.str = estrndup(value_str, value_len); + opts.input.len = value_len; + php_http_params_parse(¶ms, &opts TSRMLS_CC); + efree(opts.input.str); + + INIT_PZVAL(&arr); + array_init(&arr); + + FOREACH_HASH_KEYVAL(pos, ¶ms, key, val) { + double q; + + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("arguments"), (void *) &arg) + && IS_ARRAY == Z_TYPE_PP(arg) + && SUCCESS == zend_hash_find(Z_ARRVAL_PP(arg), ZEND_STRS("q"), (void *) &zq)) { + zval *tmp = php_http_ztyp(IS_DOUBLE, *zq); + + q = Z_DVAL_P(tmp); + zval_ptr_dtor(&tmp); + } else { + q = 1.0 - ++i / 100.0; + } + + if (key.type == HASH_KEY_IS_STRING) { + add_assoc_double_ex(&arr, key.str, key.len, q); + } else { + add_index_double(&arr, key.num, q); + } + + STR_FREE(key.str); + } + +#if 0 + zend_print_zval_r(&arr, 1 TSRMLS_CC); +#endif + + ALLOC_HASHTABLE(result); + zend_hash_init(result, zend_hash_num_elements(supported), NULL, ZVAL_PTR_DTOR, 0); + zend_hash_apply_with_arguments(supported TSRMLS_CC, php_http_negotiate_reduce, 4, Z_ARRVAL(arr), result, primary_sep_str, primary_sep_len); + zend_hash_destroy(¶ms); + zval_dtor(&arr); + zend_hash_sort(result, zend_qsort, php_http_negotiate_sort, 0 TSRMLS_CC); + } + + return result; +} + + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + + diff --git a/php_http_negotiate.h b/php_http_negotiate.h new file mode 100644 index 0000000..f31226b --- /dev/null +++ b/php_http_negotiate.h @@ -0,0 +1,140 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_NEGOTIATE_H +#define PHP_HTTP_NEGOTIATE_H + +PHP_HTTP_API HashTable *php_http_negotiate(const char *value_str, size_t value_len, HashTable *supported, const char *primary_sep_str, size_t primary_sep_len TSRMLS_DC); + +static inline HashTable *php_http_negotiate_language(HashTable *supported, php_http_message_t *request TSRMLS_DC) +{ + HashTable *result = NULL; + size_t length; + char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Language"), &length, request TSRMLS_CC); + + if (value) { + result = php_http_negotiate(value, length, supported, "-", 1 TSRMLS_CC); + } + STR_FREE(value); + + return result; +} + +static inline HashTable *php_http_negotiate_encoding(HashTable *supported, php_http_message_t *request TSRMLS_DC) +{ + HashTable *result = NULL; + size_t length; + char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Encoding"), &length, request TSRMLS_CC); + + if (value) { + result = php_http_negotiate(value, length, supported, NULL, 0 TSRMLS_CC); + } + STR_FREE(value); + + return result; +} + +static inline HashTable *php_http_negotiate_charset(HashTable *supported, php_http_message_t *request TSRMLS_DC) +{ + HashTable *result = NULL; + size_t length; + char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Charset"), &length, request TSRMLS_CC); + + if (value) { + result = php_http_negotiate(value, length, supported, NULL, 0 TSRMLS_CC); + } + STR_FREE(value); + + return result; +} + +static inline HashTable *php_http_negotiate_content_type(HashTable *supported, php_http_message_t *request TSRMLS_DC) +{ + HashTable *result = NULL; + size_t length; + char *value = php_http_env_get_request_header(ZEND_STRL("Accept"), &length, request TSRMLS_CC); + + if (value) { + result = php_http_negotiate(value, length, supported, "/", 1 TSRMLS_CC); + } + STR_FREE(value); + + return result; +} + +#define PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported) \ + { \ + zval **value; \ + \ + zend_hash_internal_pointer_reset((supported)); \ + if (SUCCESS == zend_hash_get_current_data((supported), (void *) &value)) { \ + RETVAL_ZVAL(*value, 1, 0); \ + } else { \ + RETVAL_NULL(); \ + } \ + } + +#define PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array) \ + PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \ + if (rs_array) { \ + HashPosition pos; \ + zval **value_ptr; \ + \ + FOREACH_HASH_VAL(pos, supported, value_ptr) { \ + zval *value = php_http_ztyp(IS_STRING, *value_ptr); \ + add_assoc_double(rs_array, Z_STRVAL_P(value), 1.0); \ + zval_ptr_dtor(&value); \ + } \ + } + +#define PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array) \ + { \ + char *key; \ + uint key_len; \ + ulong idx; \ + \ + if (zend_hash_num_elements(result) && HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(result, &key, &key_len, &idx, 1, NULL)) { \ + RETVAL_STRINGL(key, key_len-1, 0); \ + } else { \ + PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \ + } \ + \ + if (rs_array) { \ + zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); \ + } \ + \ + zend_hash_destroy(result); \ + FREE_HASHTABLE(result); \ + } + +#define PHP_HTTP_DO_NEGOTIATE(type, supported, rs_array) \ + { \ + HashTable *result; \ + if ((result = php_http_negotiate_ ##type(supported, NULL TSRMLS_CC))) { \ + PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array); \ + } else { \ + PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); \ + } \ + } + + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_object.c b/php_http_object.c new file mode 100644 index 0000000..d4785f1 --- /dev/null +++ b/php_http_object.c @@ -0,0 +1,91 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +zend_object_value php_http_object_new(zend_class_entry *ce TSRMLS_DC) +{ + return php_http_object_new_ex(ce, NULL, NULL TSRMLS_CC); +} + +zend_object_value php_http_object_new_ex(zend_class_entry *ce, void *nothing, php_http_object_t **ptr TSRMLS_DC) +{ + php_http_object_t *o; + + o = ecalloc(1, sizeof(php_http_object_t)); + zend_object_std_init((zend_object *) o, ce TSRMLS_CC); + object_properties_init((zend_object *) o, ce); + + if (ptr) { + *ptr = o; + } + + o->zv.handle = zend_objects_store_put(o, NULL, (zend_objects_free_object_storage_t) zend_objects_free_object_storage, NULL TSRMLS_CC); + o->zv.handlers = zend_get_std_object_handlers(); + + return o->zv; +} + +STATUS php_http_new(zend_object_value *ovp, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC) +{ + zend_object_value ov; + + if (!ce) { + ce = parent_ce; + } else if (parent_ce && !instanceof_function(ce, parent_ce TSRMLS_CC)) { + php_http_throw(unexpected_val, "Class %s does not extend %s", ce->name, parent_ce->name); + return FAILURE; + } + + ov = create(ce, intern_ptr, obj_ptr TSRMLS_CC); + if (ovp) { + *ovp = ov; + } + return SUCCESS; +} + +STATUS php_http_method_call(zval *object, const char *method_str, size_t method_len, int argc, zval **argv[], zval **retval_ptr TSRMLS_DC) +{ + zend_fcall_info fci; + zval zmethod; + zval *retval; + STATUS rv; + + fci.size = sizeof(fci); + fci.object_ptr = object; + fci.function_name = &zmethod; + fci.retval_ptr_ptr = retval_ptr ? retval_ptr : &retval; + fci.param_count = argc; + fci.params = argv; + fci.no_separation = 1; + fci.symbol_table = NULL; + fci.function_table = NULL; + + INIT_PZVAL(&zmethod); + ZVAL_STRINGL(&zmethod, method_str, method_len, 0); + rv = zend_call_function(&fci, NULL TSRMLS_CC); + + if (!retval_ptr && retval) { + zval_ptr_dtor(&retval); + } + return rv; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_object.h b/php_http_object.h new file mode 100644 index 0000000..a3786bb --- /dev/null +++ b/php_http_object.h @@ -0,0 +1,40 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_OBJECT_H +#define PHP_HTTP_OBJECT_H + +typedef struct php_http_object { + zend_object zo; + zend_object_value zv; +} php_http_object_t; + +zend_object_value php_http_object_new(zend_class_entry *ce TSRMLS_DC); +zend_object_value php_http_object_new_ex(zend_class_entry *ce, void *nothing, php_http_object_t **ptr TSRMLS_DC); + +typedef zend_object_value (*php_http_new_t)(zend_class_entry *ce, void *, void ** TSRMLS_DC); + +STATUS php_http_new(zend_object_value *ov, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC); +STATUS php_http_method_call(zval *object, const char *method_str, size_t method_len, int argc, zval **argv[], zval **retval_ptr TSRMLS_DC); + +#endif + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_options.c b/php_http_options.c new file mode 100644 index 0000000..ca455a7 --- /dev/null +++ b/php_http_options.c @@ -0,0 +1,126 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +php_http_options_t *php_http_options_init(php_http_options_t *registry, zend_bool persistent) +{ + if (!registry) { + registry = pecalloc(1, sizeof(*registry), persistent); + } else { + memset(registry, 0, sizeof(*registry)); + } + + registry->persistent = persistent; + zend_hash_init(®istry->options, 0, NULL, (dtor_func_t) zend_hash_destroy, persistent); + + return registry; +} + +STATUS php_http_options_apply(php_http_options_t *registry, HashTable *options, void *userdata) +{ + HashPosition pos; + zval *val; + php_http_option_t *opt; + + FOREACH_HASH_VAL(pos, ®istry->options, opt) { + if (!(val = registry->getter(opt, options, userdata))) { + val = &opt->defval; + } + if (registry->setter) { + if (SUCCESS != registry->setter(opt, val, userdata)) { + return FAILURE; + } + } else if (!opt->setter || SUCCESS != opt->setter(opt, val, userdata)) { + return FAILURE; + } + } + return SUCCESS; +} + +void php_http_options_dtor(php_http_options_t *registry) +{ + zend_hash_destroy(®istry->options); +} + +void php_http_options_free(php_http_options_t **registry) +{ + if (*registry) { + php_http_options_dtor(*registry); + pefree(*registry, (*registry)->persistent); + *registry = NULL; + } +} + +php_http_option_t *php_http_option_register(php_http_options_t *registry, const char *name_str, size_t name_len, ulong option, zend_uchar type) +{ + php_http_option_t opt, *dst = NULL; + + memset(&opt, 0, sizeof(opt)); + + php_http_options_init(&opt.suboptions, registry->persistent); + opt.suboptions.getter = registry->getter; + opt.suboptions.setter = registry->setter; + + opt.name.h = zend_hash_func(opt.name.s = name_str, opt.name.l = name_len + 1); + opt.type = type; + opt.option = option; + + INIT_ZVAL(opt.defval); + switch ((opt.type = type)) { + case IS_BOOL: + ZVAL_BOOL(&opt.defval, 0); + break; + + case IS_LONG: + ZVAL_LONG(&opt.defval, 0); + break; + + case IS_STRING: + ZVAL_STRINGL(&opt.defval, NULL, 0, 0); + break; + + case IS_DOUBLE: + ZVAL_DOUBLE(&opt.defval, 0); + break; + + default: + ZVAL_NULL(&opt.defval); + break; + } + + zend_hash_quick_update(®istry->options, opt.name.s, opt.name.l, opt.name.h, (void *) &opt, sizeof(opt), (void *) &dst); + return dst; +} + +zval *php_http_option_get(php_http_option_t *opt, HashTable *options, void *userdata) +{ + if (options) { + zval **zoption; + + if (SUCCESS == zend_hash_quick_find(options, opt->name.s, opt->name.l, opt->name.h, (void *) &zoption)) { + return *zoption; + } + } + + return NULL; +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_options.h b/php_http_options.h new file mode 100644 index 0000000..479b155 --- /dev/null +++ b/php_http_options.h @@ -0,0 +1,65 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_OPTIONS_H +#define PHP_HTTP_OPTIONS_H + +typedef struct php_http_option php_http_option_t; +typedef struct php_http_options php_http_options_t; + +typedef STATUS (*php_http_option_set_callback_t)(php_http_option_t *opt, zval *val, void *userdata); +typedef zval *(*php_http_option_get_callback_t)(php_http_option_t *opt, HashTable *options, void *userdata); + +struct php_http_options { + HashTable options; + + php_http_option_get_callback_t getter; + php_http_option_set_callback_t setter; + + unsigned persistent:1; +}; + +struct php_http_option { + php_http_options_t suboptions; + + struct { + const char *s; + size_t l; + ulong h; + } name; + + ulong option; + zend_uchar type; + unsigned flags; + zval defval; + + php_http_option_set_callback_t setter; +}; + +PHP_HTTP_API php_http_options_t *php_http_options_init(php_http_options_t *registry, zend_bool persistent); +PHP_HTTP_API STATUS php_http_options_apply(php_http_options_t *registry, HashTable *options, void *userdata); +PHP_HTTP_API void php_http_options_dtor(php_http_options_t *registry); +PHP_HTTP_API void php_http_options_free(php_http_options_t **registry); + +PHP_HTTP_API php_http_option_t *php_http_option_register(php_http_options_t *registry, const char *name_str, size_t name_len, ulong option, zend_uchar type); +PHP_HTTP_API zval *php_http_option_get(php_http_option_t *opt, HashTable *options, void *userdata); + +#endif /* PHP_HTTP_OPTIONS_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_params.c b/php_http_params.c new file mode 100644 index 0000000..c64df95 --- /dev/null +++ b/php_http_params.c @@ -0,0 +1,1027 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +static php_http_params_token_t def_param_sep = {",", 1}, *def_param_sep_ptr[] = {&def_param_sep, NULL}; +static php_http_params_token_t def_arg_sep = {";", 1}, *def_arg_sep_ptr[] = {&def_arg_sep, NULL}; +static php_http_params_token_t def_val_sep = {"=", 1}, *def_val_sep_ptr[] = {&def_val_sep, NULL}; +static php_http_params_opts_t def_opts = { + {NULL, 0}, + def_param_sep_ptr, + def_arg_sep_ptr, + def_val_sep_ptr, + NULL, + PHP_HTTP_PARAMS_DEFAULT +}; + +php_http_params_opts_t *php_http_params_opts_default_get(php_http_params_opts_t *opts) +{ + if (!opts) { + opts = emalloc(sizeof(*opts)); + } + + memcpy(opts, &def_opts, sizeof(def_opts)); + + return opts; +} + +typedef struct php_http_params_state { + php_http_params_token_t input; + php_http_params_token_t param; + php_http_params_token_t arg; + php_http_params_token_t val; + struct { + zval **param; + zval **args; + zval **val; + } current; + unsigned quotes:1; + unsigned escape:1; +} php_http_params_state_t; + +static inline void sanitize_default(zval *zv TSRMLS_DC) +{ + if (Z_STRVAL_P(zv)[0] == '"' && Z_STRVAL_P(zv)[Z_STRLEN_P(zv) - 1] == '"') { + size_t deq_len = Z_STRLEN_P(zv) - 2; + char *deq = estrndup(Z_STRVAL_P(zv) + 1, deq_len); + + zval_dtor(zv); + ZVAL_STRINGL(zv, deq, deq_len, 0); + } + + php_stripslashes(Z_STRVAL_P(zv), &Z_STRLEN_P(zv) TSRMLS_CC); +} + +static inline void prepare_default(zval *zv TSRMLS_DC) +{ + if (Z_TYPE_P(zv) == IS_STRING) { + int len = Z_STRLEN_P(zv); + + Z_STRVAL_P(zv) = php_addslashes(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &Z_STRLEN_P(zv), 1 TSRMLS_CC); + + if (len != Z_STRLEN_P(zv)) { + zval tmp = *zv; + int len = Z_STRLEN_P(zv) + 2; + char *str = emalloc(len + 1); + + str[0] = '"'; + memcpy(&str[1], Z_STRVAL_P(zv), Z_STRLEN_P(zv)); + str[len-1] = '"'; + str[len] = '\0'; + + zval_dtor(&tmp); + ZVAL_STRINGL(zv, str, len, 0); + } + } else { + zval_dtor(zv); + ZVAL_EMPTY_STRING(zv); + } +} + +static inline void sanitize_urlencoded(zval *zv TSRMLS_DC) +{ + Z_STRLEN_P(zv) = php_raw_url_decode(Z_STRVAL_P(zv), Z_STRLEN_P(zv)); +} + +static inline void prepare_urlencoded(zval *zv TSRMLS_DC) +{ + int len; + char *str = php_url_encode(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &len); + + zval_dtor(zv); + ZVAL_STRINGL(zv, str, len, 0); +} + +static void sanitize_dimension(zval *zv TSRMLS_DC) +{ + zval *arr = NULL, *tmp = NULL, **cur = NULL; + char *var = NULL, *ptr = Z_STRVAL_P(zv), *end = Z_STRVAL_P(zv) + Z_STRLEN_P(zv); + long level = 0; + + MAKE_STD_ZVAL(arr); + array_init(arr); + cur = &arr; + + while (ptr < end) { + if (!var) { + var = ptr; + } + + switch (*ptr) { + case '[': + if (++level > PG(max_input_nesting_level)) { + zval_ptr_dtor(&arr); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Max input nesting level of %ld exceeded", (long) PG(max_input_nesting_level)); + return; + } + if (ptr - var == 0) { + ++var; + break; + } + /* no break */ + + case ']': + + MAKE_STD_ZVAL(tmp); + ZVAL_NULL(tmp); + convert_to_array(*cur); + + if (ptr - var) { + char chr = *ptr; + *ptr = '\0'; + zend_symtable_update(Z_ARRVAL_PP(cur), var, ptr - var + 1, (void *) &tmp, sizeof(zval *), (void *) &cur); + *ptr = chr; + } else { + zend_hash_next_index_insert(Z_ARRVAL_PP(cur), (void *) &tmp, sizeof(zval *), (void *) &cur); + } + + var = NULL; + break; + } + + ++ptr; + } + + if (zend_hash_num_elements(Z_ARRVAL_P(arr))) { + zval_dtor(zv); +#if PHP_VERSION_ID >= 50400 + ZVAL_COPY_VALUE(zv, arr); +#else + zv->value = arr->value; + Z_TYPE_P(zv) = Z_TYPE_P(arr); +#endif + FREE_ZVAL(arr); + } else { + zval_ptr_dtor(&arr); + } +} + +static inline void shift_key(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags TSRMLS_DC); +static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC); + +static void prepare_dimension(php_http_buffer_t *buf, php_http_buffer_t *keybuf, zval *zvalue, const char *pss, size_t psl, const char *vss, size_t vsl, unsigned flags TSRMLS_DC) +{ + HashTable *ht = HASH_OF(zvalue); + HashPosition pos; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + zval **val; + php_http_buffer_t prefix; + + if (!ht->nApplyCount++) { + php_http_buffer_init(&prefix); + php_http_buffer_append(&prefix, keybuf->data, keybuf->used); + + FOREACH_HASH_KEYVAL(pos, ht, key, val) { + if (key.type == HASH_KEY_IS_STRING && !*key.str) { + /* only public properties */ + continue; + } + + php_http_buffer_appends(&prefix, "["); + if (key.type == HASH_KEY_IS_STRING) { + php_http_buffer_append(&prefix, key.str, key.len - 1); + } else { + php_http_buffer_appendf(&prefix, "%lu", key.num); + } + php_http_buffer_appends(&prefix, "]"); + + if (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT) { + prepare_dimension(buf, &prefix, *val, pss, psl, vss, vsl, flags TSRMLS_CC); + } else { + zval *cpy = php_http_ztyp(IS_STRING, *val); + + shift_key(buf, prefix.data, prefix.used, pss, psl, flags TSRMLS_CC); + shift_val(buf, cpy, vss, vsl, flags TSRMLS_CC); + zval_ptr_dtor(&cpy); + } + + php_http_buffer_cut(&prefix, keybuf->used, prefix.used - keybuf->used); + } + php_http_buffer_dtor(&prefix); + } + --ht->nApplyCount; +} + +static inline void sanitize_key(unsigned flags, char *str, size_t len, zval *zv TSRMLS_DC) +{ + zval_dtor(zv); + php_trim(str, len, NULL, 0, zv, 3 TSRMLS_CC); + + if (flags & PHP_HTTP_PARAMS_DEFAULT) { + sanitize_default(zv TSRMLS_CC); + } + + if (flags & PHP_HTTP_PARAMS_URLENCODED) { + sanitize_urlencoded(zv TSRMLS_CC); + } + + if (flags & PHP_HTTP_PARAMS_DIMENSION) { + sanitize_dimension(zv TSRMLS_CC); + } +} + +static inline void sanitize_value(unsigned flags, char *str, size_t len, zval *zv TSRMLS_DC) +{ + zval_dtor(zv); + php_trim(str, len, NULL, 0, zv, 3 TSRMLS_CC); + + if (flags & PHP_HTTP_PARAMS_DEFAULT) { + sanitize_default(zv TSRMLS_CC); + } + + if (flags & PHP_HTTP_PARAMS_URLENCODED) { + sanitize_urlencoded(zv TSRMLS_CC); + } +} + +static inline void prepare_key(unsigned flags, char *old_key, size_t old_len, char **new_key, size_t *new_len TSRMLS_DC) +{ + zval zv; + + INIT_PZVAL(&zv); + ZVAL_STRINGL(&zv, old_key, old_len, 1); + + if (flags & PHP_HTTP_PARAMS_URLENCODED) { + prepare_urlencoded(&zv TSRMLS_CC); + } + + if (flags & PHP_HTTP_PARAMS_DEFAULT) { + prepare_default(&zv TSRMLS_CC); + } + + *new_key = Z_STRVAL(zv); + *new_len = Z_STRLEN(zv); +} + +static inline void prepare_value(unsigned flags, zval *zv TSRMLS_DC) +{ + if (flags & PHP_HTTP_PARAMS_URLENCODED) { + prepare_urlencoded(zv TSRMLS_CC); + } + + if (flags & PHP_HTTP_PARAMS_DEFAULT) { + prepare_default(zv TSRMLS_CC); + } +} + +static void merge_param(HashTable *params, zval *zdata, zval ***current_param, zval ***current_args TSRMLS_DC) +{ + zval **ptr, **zdata_ptr; + php_http_array_hashkey_t hkey = php_http_array_hashkey_init(0); + +#if 0 + { + zval tmp; + INIT_PZVAL_ARRAY(&tmp, params); + fprintf(stderr, "params = "); + zend_print_zval_r(&tmp, 1 TSRMLS_CC); + fprintf(stderr, "\n"); + } +#endif + + hkey.type = zend_hash_get_current_key_ex(Z_ARRVAL_P(zdata), &hkey.str, &hkey.len, &hkey.num, hkey.dup, NULL); + + if ((hkey.type == HASH_KEY_IS_STRING && !zend_hash_exists(params, hkey.str, hkey.len)) + || (hkey.type == HASH_KEY_IS_LONG && !zend_hash_index_exists(params, hkey.num)) + ) { + zval *tmp, *arg, **args; + + /* create the entry if it doesn't exist */ + zend_hash_get_current_data(Z_ARRVAL_P(zdata), (void *) &ptr); + Z_ADDREF_PP(ptr); + MAKE_STD_ZVAL(tmp); + array_init(tmp); + add_assoc_zval_ex(tmp, ZEND_STRS("value"), *ptr); + + MAKE_STD_ZVAL(arg); + array_init(arg); + zend_hash_update(Z_ARRVAL_P(tmp), "arguments", sizeof("arguments"), (void *) &arg, sizeof(zval *), (void *) &args); + *current_args = args; + + if (hkey.type == HASH_KEY_IS_STRING) { + zend_hash_update(params, hkey.str, hkey.len, (void *) &tmp, sizeof(zval *), (void *) &ptr); + } else { + zend_hash_index_update(params, hkey.num, (void *) &tmp, sizeof(zval *), (void *) &ptr); + } + } else { + /* merge */ + if (hkey.type == HASH_KEY_IS_STRING) { + zend_hash_find(params, hkey.str, hkey.len, (void *) &ptr); + } else { + zend_hash_index_find(params, hkey.num, (void *) &ptr); + } + + zdata_ptr = &zdata; + + if (Z_TYPE_PP(ptr) == IS_ARRAY + && SUCCESS == zend_hash_find(Z_ARRVAL_PP(ptr), "value", sizeof("value"), (void *) &ptr) + && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_PP(zdata_ptr), (void *) &zdata_ptr) + ) { + /* + * params = [arr => [value => [0 => 1]]] + * ^- ptr + * zdata = [arr => [0 => NULL]] + * ^- zdata_ptr + */ + zval **test_ptr; + + while (Z_TYPE_PP(zdata_ptr) == IS_ARRAY + && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_PP(zdata_ptr), (void *) &test_ptr) + ) { + if (Z_TYPE_PP(test_ptr) == IS_ARRAY) { + + /* now find key in ptr */ + if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_PP(zdata_ptr), &hkey.str, &hkey.len, &hkey.num, hkey.dup, NULL)) { + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(ptr), hkey.str, hkey.len, (void *) &ptr)) { + zdata_ptr = test_ptr; + } else { + Z_ADDREF_PP(test_ptr); + zend_hash_update(Z_ARRVAL_PP(ptr), hkey.str, hkey.len, (void *) test_ptr, sizeof(zval *), (void *) &ptr); + break; + } + } else { + if (SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(ptr), hkey.num, (void *) &ptr)) { + zdata_ptr = test_ptr; + } else if (hkey.num) { + Z_ADDREF_PP(test_ptr); + zend_hash_index_update(Z_ARRVAL_PP(ptr), hkey.num, (void *) test_ptr, sizeof(zval *), (void *) &ptr); + break; + } else { + Z_ADDREF_PP(test_ptr); + zend_hash_next_index_insert(Z_ARRVAL_PP(ptr), (void *) test_ptr, sizeof(zval *), (void *) &ptr); + break; + } + } + } else { + /* this is the leaf */ + Z_ADDREF_PP(test_ptr); + if (Z_TYPE_PP(ptr) != IS_ARRAY) { + zval_dtor(*ptr); + array_init(*ptr); + } + if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_PP(zdata_ptr), &hkey.str, &hkey.len, &hkey.num, hkey.dup, NULL)) { + zend_hash_update(Z_ARRVAL_PP(ptr), hkey.str, hkey.len, (void *) test_ptr, sizeof(zval *), (void *) &ptr); + } else if (hkey.num) { + zend_hash_index_update(Z_ARRVAL_PP(ptr), hkey.num, (void *) test_ptr, sizeof(zval *), (void *) &ptr); + } else { + zend_hash_next_index_insert(Z_ARRVAL_PP(ptr), (void *) test_ptr, sizeof(zval *), (void *) &ptr); + } + break; + } + } + + } + } + + /* bubble up */ + while (Z_TYPE_PP(ptr) == IS_ARRAY && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_PP(ptr), (void *) &ptr)); + *current_param = ptr; +} + +static void push_param(HashTable *params, php_http_params_state_t *state, const php_http_params_opts_t *opts TSRMLS_DC) +{ + if (state->val.str) { + if (0 < (state->val.len = state->input.str - state->val.str)) { + sanitize_value(opts->flags, state->val.str, state->val.len, *(state->current.val) TSRMLS_CC); + } + } else if (state->arg.str) { + if (0 < (state->arg.len = state->input.str - state->arg.str)) { + zval *val, key; + + INIT_PZVAL(&key); + ZVAL_NULL(&key); + sanitize_key(opts->flags, state->arg.str, state->arg.len, &key TSRMLS_CC); + if (Z_TYPE(key) == IS_STRING && Z_STRLEN(key)) { + MAKE_STD_ZVAL(val); + ZVAL_TRUE(val); + zend_symtable_update(Z_ARRVAL_PP(state->current.args), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.val); + } + zval_dtor(&key); + } + } else if (state->param.str) { + if (0 < (state->param.len = state->input.str - state->param.str)) { + zval *prm, *arg, *val, *key; + + MAKE_STD_ZVAL(key); + ZVAL_NULL(key); + sanitize_key(opts->flags, state->param.str, state->param.len, key TSRMLS_CC); + if (Z_TYPE_P(key) != IS_STRING) { + merge_param(params, key, &state->current.val, &state->current.args TSRMLS_CC); + } else if (Z_STRLEN_P(key)) { + MAKE_STD_ZVAL(prm); + array_init(prm); + + MAKE_STD_ZVAL(val); + if (opts->defval) { + ZVAL_COPY_VALUE(val, opts->defval); + zval_copy_ctor(val); + } else { + ZVAL_TRUE(val); + } + zend_hash_update(Z_ARRVAL_P(prm), "value", sizeof("value"), (void *) &val, sizeof(zval *), (void *) &state->current.val); + + MAKE_STD_ZVAL(arg); + array_init(arg); + zend_hash_update(Z_ARRVAL_P(prm), "arguments", sizeof("arguments"), (void *) &arg, sizeof(zval *), (void *) &state->current.args); + + zend_symtable_update(params, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void *) &prm, sizeof(zval *), (void *) &state->current.param); + } + zval_ptr_dtor(&key); + } + } +} + +static inline zend_bool check_str(const char *chk_str, size_t chk_len, const char *sep_str, size_t sep_len) { + return 0 < sep_len && chk_len >= sep_len && !memcmp(chk_str, sep_str, sep_len); +} + +static size_t check_sep(php_http_params_state_t *state, php_http_params_token_t **separators) +{ + php_http_params_token_t **sep = separators; + + if (state->quotes || state->escape) { + return 0; + } + + if (sep) while (*sep) { + if (check_str(state->input.str, state->input.len, (*sep)->str, (*sep)->len)) { + return (*sep)->len; + } + ++sep; + } + return 0; +} + +static void skip_sep(size_t skip, php_http_params_state_t *state, php_http_params_token_t **param, php_http_params_token_t **arg, php_http_params_token_t **val TSRMLS_DC) +{ + size_t sep_len; + + state->input.str += skip; + state->input.len -= skip; + + while ( (param && (sep_len = check_sep(state, param))) + || (arg && (sep_len = check_sep(state, arg))) + || (val && (sep_len = check_sep(state, val))) + ) { + state->input.str += sep_len; + state->input.len -= sep_len; + } +} + +HashTable *php_http_params_parse(HashTable *params, const php_http_params_opts_t *opts TSRMLS_DC) +{ + php_http_params_state_t state = {{NULL,0}, {NULL,0}, {NULL,0}, {NULL,0}, {NULL,NULL,NULL}, 0, 0}; + + state.input.str = opts->input.str; + state.input.len = opts->input.len; + + if (!params) { + ALLOC_HASHTABLE(params); + ZEND_INIT_SYMTABLE(params); + } + + while (state.input.len) { + if (*state.input.str == '"' && !state.escape) { + state.quotes = !state.quotes; + } else { + state.escape = (*state.input.str == '\\'); + } + + if (!state.param.str) { + /* initialize */ + skip_sep(0, &state, opts->param, opts->arg, opts->val TSRMLS_CC); + state.param.str = state.input.str; + } else { + size_t sep_len; + /* are we at a param separator? */ + if (0 < (sep_len = check_sep(&state, opts->param))) { + push_param(params, &state, opts TSRMLS_CC); + + skip_sep(sep_len, &state, opts->param, opts->arg, opts->val TSRMLS_CC); + + /* start off with a new param */ + state.param.str = state.input.str; + state.param.len = 0; + state.arg.str = NULL; + state.arg.len = 0; + state.val.str = NULL; + state.val.len = 0; + + continue; + + } else + /* are we at an arg separator? */ + if (0 < (sep_len = check_sep(&state, opts->arg))) { + push_param(params, &state, opts TSRMLS_CC); + + skip_sep(sep_len, &state, NULL, opts->arg, opts->val TSRMLS_CC); + + /* continue with a new arg */ + state.arg.str = state.input.str; + state.arg.len = 0; + state.val.str = NULL; + state.val.len = 0; + + continue; + + } else + /* are we at a val separator? */ + if (0 < (sep_len = check_sep(&state, opts->val))) { + /* only handle separator if we're not already reading in a val */ + if (!state.val.str) { + push_param(params, &state, opts TSRMLS_CC); + + skip_sep(sep_len, &state, NULL, NULL, opts->val TSRMLS_CC); + + state.val.str = state.input.str; + state.val.len = 0; + + continue; + } + } + } + + if (state.input.len) { + ++state.input.str; + --state.input.len; + } + } + /* finalize */ + push_param(params, &state, opts TSRMLS_CC); + + return params; +} + +static inline void shift_key(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags TSRMLS_DC) +{ + char *str; + size_t len; + + if (buf->used) { + php_http_buffer_append(buf, ass, asl); + } + + prepare_key(flags, key_str, key_len, &str, &len TSRMLS_CC); + php_http_buffer_append(buf, str, len); + efree(str); +} + +static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC) +{ + if (Z_TYPE_P(zvalue) != IS_BOOL) { + zval *tmp = php_http_zsep(1, IS_STRING, zvalue); + + prepare_value(flags, tmp TSRMLS_CC); + php_http_buffer_append(buf, vss, vsl); + php_http_buffer_append(buf, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + + zval_ptr_dtor(&tmp); + } else if (!Z_BVAL_P(zvalue)) { + php_http_buffer_append(buf, vss, vsl); + php_http_buffer_appends(buf, "0"); + } +} + +static void shift_arg(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags TSRMLS_DC) +{ + if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) { + HashPosition pos; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + zval **val; + + shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC); + FOREACH_KEYVAL(pos, zvalue, key, val) { + /* did you mean recursion? */ + php_http_array_hashkey_stringify(&key); + shift_arg(buf, key.str, key.len-1, *val, ass, asl, vss, vsl, flags TSRMLS_CC); + php_http_array_hashkey_stringfree(&key); + } + } else { + shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC); + shift_val(buf, zvalue, vss, vsl, flags TSRMLS_CC); + } +} + +static void shift_param(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags TSRMLS_DC) +{ + if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) { + /* treat as arguments, unless we care for dimensions */ + if (flags & PHP_HTTP_PARAMS_DIMENSION) { + php_http_buffer_t *keybuf = php_http_buffer_from_string(key_str, key_len); + prepare_dimension(buf, keybuf, zvalue, pss, psl, vss, vsl, flags TSRMLS_CC); + php_http_buffer_free(&keybuf); + } else { + shift_arg(buf, key_str, key_len, zvalue, ass, asl, vss, vsl, flags TSRMLS_CC); + } + } else { + shift_key(buf, key_str, key_len, pss, psl, flags TSRMLS_CC); + shift_val(buf, zvalue, vss, vsl, flags TSRMLS_CC); + } +} + +php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *params, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags TSRMLS_DC) +{ + zval **zparam; + HashPosition pos, pos1; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0), key1 = php_http_array_hashkey_init(0); + + if (!buf) { + buf = php_http_buffer_init(NULL); + } + + FOREACH_HASH_KEYVAL(pos, params, key, zparam) { + zval **zvalue, **zargs; + + if (Z_TYPE_PP(zparam) != IS_ARRAY || SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("value"), (void *) &zvalue)) { + zvalue = zparam; + } + + php_http_array_hashkey_stringify(&key); + shift_param(buf, key.str, key.len - 1, *zvalue, pss, psl, ass, asl, vss, vsl, flags TSRMLS_CC); + php_http_array_hashkey_stringfree(&key); + + if (Z_TYPE_PP(zparam) == IS_ARRAY && SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("arguments"), (void *) &zvalue)) { + if (zvalue == zparam) { + continue; + } + zvalue = zparam; + } + + if (Z_TYPE_PP(zvalue) == IS_ARRAY) { + FOREACH_KEYVAL(pos1, *zvalue, key1, zargs) { + if (zvalue == zparam && key1.type == HASH_KEY_IS_STRING && !strcmp(key1.str, "value")) { + continue; + } + + php_http_array_hashkey_stringify(&key1); + shift_arg(buf, key1.str, key1.len - 1, *zargs, ass, asl, vss, vsl, flags TSRMLS_CC); + php_http_array_hashkey_stringfree(&key1); + } + } + } + + php_http_buffer_shrink(buf); + php_http_buffer_fix(buf); + + return buf; +} + +php_http_params_token_t **php_http_params_separator_init(zval *zv TSRMLS_DC) +{ + zval **sep; + HashPosition pos; + php_http_params_token_t **ret, **tmp; + + if (!zv) { + return NULL; + } + + zv = php_http_ztyp(IS_ARRAY, zv); + ret = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(zv)) + 1, sizeof(*ret)); + + tmp = ret; + FOREACH_VAL(pos, zv, sep) { + zval *zt = php_http_ztyp(IS_STRING, *sep); + + if (Z_STRLEN_P(zt)) { + *tmp = emalloc(sizeof(**tmp)); + (*tmp)->str = estrndup(Z_STRVAL_P(zt), (*tmp)->len = Z_STRLEN_P(zt)); + ++tmp; + } + zval_ptr_dtor(&zt); + } + zval_ptr_dtor(&zv); + + *tmp = NULL; + return ret; +} + +void php_http_params_separator_free(php_http_params_token_t **separator) +{ + php_http_params_token_t **sep = separator; + if (sep) { + while (*sep) { + STR_FREE((*sep)->str); + efree(*sep); + ++sep; + } + efree(separator); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams___construct, 0, 0, 0) + ZEND_ARG_INFO(0, params) + ZEND_ARG_INFO(0, param_sep) + ZEND_ARG_INFO(0, arg_sep) + ZEND_ARG_INFO(0, val_sep) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpParams, __construct) +{ + zval *zcopy, *zparams = NULL, *param_sep = NULL, *arg_sep = NULL, *val_sep = NULL; + long flags = PHP_HTTP_PARAMS_DEFAULT; + zend_error_handling zeh; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!/z/z/z/l", &zparams, ¶m_sep, &arg_sep, &val_sep, &flags), invalid_arg, return); + + zend_replace_error_handling(EH_THROW, php_http_exception_runtime_class_entry, &zeh TSRMLS_CC); + { + switch (ZEND_NUM_ARGS()) { + case 5: + zend_update_property_long(php_http_params_class_entry, getThis(), ZEND_STRL("flags"), flags TSRMLS_CC); + /* no break */ + case 4: + zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("val_sep"), val_sep TSRMLS_CC); + /* no break */ + case 3: + zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("arg_sep"), arg_sep TSRMLS_CC); + /* no break */ + case 2: + zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("param_sep"), param_sep TSRMLS_CC); + /* no break */ + } + + if (zparams) { + switch (Z_TYPE_P(zparams)) { + case IS_OBJECT: + case IS_ARRAY: + zcopy = php_http_zsep(1, IS_ARRAY, zparams); + zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zcopy TSRMLS_CC); + zval_ptr_dtor(&zcopy); + break; + default: + zcopy = php_http_ztyp(IS_STRING, zparams); + if (Z_STRLEN_P(zcopy)) { + php_http_params_opts_t opts = { + {Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy)}, + php_http_params_separator_init(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("param_sep"), 0 TSRMLS_CC) TSRMLS_CC), + php_http_params_separator_init(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("arg_sep"), 0 TSRMLS_CC) TSRMLS_CC), + php_http_params_separator_init(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("val_sep"), 0 TSRMLS_CC) TSRMLS_CC), + NULL, flags + }; + + MAKE_STD_ZVAL(zparams); + array_init(zparams); + php_http_params_parse(Z_ARRVAL_P(zparams), &opts TSRMLS_CC); + zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC); + zval_ptr_dtor(&zparams); + + php_http_params_separator_free(opts.param); + php_http_params_separator_free(opts.arg); + php_http_params_separator_free(opts.val); + } + zval_ptr_dtor(&zcopy); + break; + } + } else { + MAKE_STD_ZVAL(zparams); + array_init(zparams); + zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC); + zval_ptr_dtor(&zparams); + } + } + zend_restore_error_handling(&zeh TSRMLS_CC); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_toArray, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpParams, toArray) +{ + zval *zparams; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + zparams = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC); + RETURN_ZVAL(zparams, 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_toString, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpParams, toString) +{ + zval **tmp, *zparams, *zpsep, *zasep, *zvsep, *zflags; + php_http_buffer_t buf; + + zparams = php_http_zsep(1, IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC)); + zflags = php_http_ztyp(IS_LONG, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("flags"), 0 TSRMLS_CC)); + + zpsep = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("param_sep"), 0 TSRMLS_CC); + if (Z_TYPE_P(zpsep) == IS_ARRAY && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zpsep), (void *) &tmp)) { + zpsep = php_http_ztyp(IS_STRING, *tmp); + } else { + zpsep = php_http_ztyp(IS_STRING, zpsep); + } + zasep = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("arg_sep"), 0 TSRMLS_CC); + if (Z_TYPE_P(zasep) == IS_ARRAY && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zasep), (void *) &tmp)) { + zasep = php_http_ztyp(IS_STRING, *tmp); + } else { + zasep = php_http_ztyp(IS_STRING, zasep); + } + zvsep = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("val_sep"), 0 TSRMLS_CC); + if (Z_TYPE_P(zvsep) == IS_ARRAY && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zvsep), (void *) &tmp)) { + zvsep = php_http_ztyp(IS_STRING, *tmp); + } else { + zvsep = php_http_ztyp(IS_STRING, zvsep); + } + + php_http_buffer_init(&buf); + php_http_params_to_string(&buf, Z_ARRVAL_P(zparams), Z_STRVAL_P(zpsep), Z_STRLEN_P(zpsep), Z_STRVAL_P(zasep), Z_STRLEN_P(zasep), Z_STRVAL_P(zvsep), Z_STRLEN_P(zvsep), Z_LVAL_P(zflags) TSRMLS_CC); + + zval_ptr_dtor(&zparams); + zval_ptr_dtor(&zpsep); + zval_ptr_dtor(&zasep); + zval_ptr_dtor(&zvsep); + zval_ptr_dtor(&zflags); + + RETVAL_PHP_HTTP_BUFFER_VAL(&buf); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetExists, 0, 0, 1) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpParams, offsetExists) +{ + char *name_str; + int name_len; + zval **zparam, *zparams; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) { + return; + } + + zparams = php_http_ztyp(IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC)); + + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(zparams), name_str, name_len + 1, (void *) &zparam)) { + RETVAL_BOOL(Z_TYPE_PP(zparam) != IS_NULL); + } else { + RETVAL_FALSE; + } + zval_ptr_dtor(&zparams); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpParams, offsetGet) +{ + char *name_str; + int name_len; + zval **zparam, *zparams; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) { + return; + } + + zparams = php_http_ztyp(IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC)); + + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(zparams), name_str, name_len + 1, (void *) &zparam)) { + RETVAL_ZVAL(*zparam, 1, 0); + } + + zval_ptr_dtor(&zparams); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetUnset, 0, 0, 1) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpParams, offsetUnset) +{ + char *name_str; + int name_len; + zval *zparams; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) { + return; + } + + zparams = php_http_zsep(1, IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC)); + + zend_symtable_del(Z_ARRVAL_P(zparams), name_str, name_len + 1); + zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC); + + zval_ptr_dtor(&zparams); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, name) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpParams, offsetSet) +{ + zval *nvalue; + char *name_str; + int name_len; + zval **zparam, *zparams; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name_str, &name_len, &nvalue)) { + return; + } + + zparams = php_http_zsep(1, IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC)); + + if (name_len) { + if (Z_TYPE_P(nvalue) == IS_ARRAY) { + zval *new_zparam; + + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(zparams), name_str, name_len + 1, (void *) &zparam)) { + new_zparam = php_http_zsep(1, IS_ARRAY, *zparam); + array_join(Z_ARRVAL_P(nvalue), Z_ARRVAL_P(new_zparam), 0, 0); + } else { + new_zparam = nvalue; + Z_ADDREF_P(new_zparam); + } + add_assoc_zval_ex(zparams, name_str, name_len + 1, new_zparam); + } else { + zval *tmp; + + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(zparams), name_str, name_len + 1, (void *) &zparam)) { + tmp = php_http_zsep(1, IS_ARRAY, *zparam); + } else { + MAKE_STD_ZVAL(tmp); + array_init(tmp); + } + + Z_ADDREF_P(nvalue); + add_assoc_zval_ex(tmp, ZEND_STRS("value"), nvalue); + add_assoc_zval_ex(zparams, name_str, name_len + 1, tmp); + } + } else { + zval *tmp = php_http_ztyp(IS_STRING, nvalue), *arr; + + MAKE_STD_ZVAL(arr); + array_init(arr); + add_assoc_bool_ex(arr, ZEND_STRS("value"), 1); + add_assoc_zval_ex(zparams, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp) + 1, arr); + zval_ptr_dtor(&tmp); + } + + zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC); + zval_ptr_dtor(&zparams); +} + +static zend_function_entry php_http_params_methods[] = { + PHP_ME(HttpParams, __construct, ai_HttpParams___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL) + + PHP_ME(HttpParams, toArray, ai_HttpParams_toArray, ZEND_ACC_PUBLIC) + PHP_ME(HttpParams, toString, ai_HttpParams_toString, ZEND_ACC_PUBLIC) + ZEND_MALIAS(HttpParams, __toString, toString, ai_HttpParams_toString, ZEND_ACC_PUBLIC) + + PHP_ME(HttpParams, offsetExists, ai_HttpParams_offsetExists, ZEND_ACC_PUBLIC) + PHP_ME(HttpParams, offsetUnset, ai_HttpParams_offsetUnset, ZEND_ACC_PUBLIC) + PHP_ME(HttpParams, offsetSet, ai_HttpParams_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(HttpParams, offsetGet, ai_HttpParams_offsetGet, ZEND_ACC_PUBLIC) + + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_params_class_entry; + +PHP_MINIT_FUNCTION(http_params) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "Params", php_http_params_methods); + php_http_params_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + php_http_params_class_entry->create_object = php_http_params_object_new; + zend_class_implements(php_http_params_class_entry TSRMLS_CC, 1, zend_ce_arrayaccess); + + zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_PARAM_SEP"), ZEND_STRL(",") TSRMLS_CC); + zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_ARG_SEP"), ZEND_STRL(";") TSRMLS_CC); + zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_VAL_SEP"), ZEND_STRL("=") TSRMLS_CC); + zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("COOKIE_PARAM_SEP"), ZEND_STRL("") TSRMLS_CC); + + zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_PARAMS_RAW TSRMLS_CC); + zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DEFAULT"), PHP_HTTP_PARAMS_DEFAULT TSRMLS_CC); + zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_URLENCODED"), PHP_HTTP_PARAMS_URLENCODED TSRMLS_CC); + zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DIMENSION"), PHP_HTTP_PARAMS_DIMENSION TSRMLS_CC); + zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_QUERY"), PHP_HTTP_PARAMS_QUERY TSRMLS_CC); + + zend_declare_property_null(php_http_params_class_entry, ZEND_STRL("params"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("param_sep"), ZEND_STRL(","), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("arg_sep"), ZEND_STRL(";"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("val_sep"), ZEND_STRL("="), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_long(php_http_params_class_entry, ZEND_STRL("flags"), PHP_HTTP_PARAMS_DEFAULT, ZEND_ACC_PUBLIC TSRMLS_CC); + + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_params.h b/php_http_params.h new file mode 100644 index 0000000..a9ac564 --- /dev/null +++ b/php_http_params.h @@ -0,0 +1,62 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_PARAMS_H +#define PHP_HTTP_PARAMS_H + +typedef struct php_http_params_token { + char *str; + size_t len; +} php_http_params_token_t; + +#define PHP_HTTP_PARAMS_RAW 0x00 +#define PHP_HTTP_PARAMS_DEFAULT 0x01 +#define PHP_HTTP_PARAMS_URLENCODED 0x04 +#define PHP_HTTP_PARAMS_DIMENSION 0x08 +#define PHP_HTTP_PARAMS_QUERY (PHP_HTTP_PARAMS_URLENCODED|PHP_HTTP_PARAMS_DIMENSION) + +typedef struct php_http_params_opts { + php_http_params_token_t input; + php_http_params_token_t **param; + php_http_params_token_t **arg; + php_http_params_token_t **val; + zval *defval; + unsigned flags; +} php_http_params_opts_t; + +PHP_HTTP_API php_http_params_opts_t *php_http_params_opts_default_get(php_http_params_opts_t *opts); +PHP_HTTP_API HashTable *php_http_params_parse(HashTable *params, const php_http_params_opts_t *opts TSRMLS_DC); +PHP_HTTP_API php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *params, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags TSRMLS_DC); + +PHP_HTTP_API php_http_params_token_t **php_http_params_separator_init(zval *zv TSRMLS_DC); +PHP_HTTP_API void php_http_params_separator_free(php_http_params_token_t **separator); + +typedef php_http_object_t php_http_params_object_t; + +PHP_HTTP_API zend_class_entry *php_http_params_class_entry; + +PHP_MINIT_FUNCTION(http_params); + +#define php_http_params_object_new php_http_object_new +#define php_http_params_object_new_ex php_http_object_new_ex + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_persistent_handle_api.h b/php_http_persistent_handle_api.h deleted file mode 100644 index 87868df..0000000 --- a/php_http_persistent_handle_api.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef HTTP_PERSISTENT_HANDLE_H -#define HTTP_PERSISTENT_HANDLE_H - -typedef void *(*http_persistent_handle_ctor)(void); -typedef void (*http_persistent_handle_dtor)(void *handle); -typedef void *(*http_persistent_handle_copy)(void *handle); - -PHP_MINIT_FUNCTION(http_persistent_handle); -PHP_MSHUTDOWN_FUNCTION(http_persistent_handle); - -#define http_persistent_handle_provide(n, c, d, cc) _http_persistent_handle_provide_ex((n), strlen(n), (c), (d), (cc)) -#define http_persistent_handle_provide_ex(n, l, c, d, cc) _http_persistent_handle_provide_ex((n), (l), (c), (d), (cc)) -PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, size_t name_len, http_persistent_handle_ctor ctor, http_persistent_handle_dtor dtor, http_persistent_handle_copy copy); - -#define http_persistent_handle_cleanup(n, c) _http_persistent_handle_cleanup_ex((n), strlen(n), (c) TSRMLS_CC) -#define http_persistent_handle_cleanup_ex(n, l,c ) _http_persistent_handle_cleanup_ex((n), (l), (c) TSRMLS_CC) -PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC); - -#define http_persistent_handle_statall() _http_persistent_handle_statall_ex(NULL TSRMLS_CC) -#define http_persistent_handle_statall_ex(ht) _http_persistent_handle_statall_ex((ht) TSRMLS_CC) -PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht TSRMLS_DC); - -#define http_persistent_handle_acquire(n, h) _http_persistent_handle_acquire_ex((n), strlen(n), (h) TSRMLS_CC) -#define http_persistent_handle_acquire_ex(n, l, h) _http_persistent_handle_acquire_ex((n), (l), (h) TSRMLS_CC) -PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC); - -#define http_persistent_handle_release(n, h) _http_persistent_handle_release_ex((n), strlen(n), (h) TSRMLS_CC) -#define http_persistent_handle_release_ex(n, l, h) _http_persistent_handle_release_ex((n), (l), (h) TSRMLS_CC) -PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC); - -#define http_persistent_handle_accrete(n, oh, nh) _http_persistent_handle_accrete_ex((n), strlen(n), (oh), (nh) TSRMLS_CC) -#define http_persistent_handle_accrete_ex(n, l, oh, nh) _http_persistent_handle_accrete_ex((n), (l), (oh), (nh) TSRMLS_CC) -PHP_HTTP_API STATUS _http_persistent_handle_accrete_ex(const char *name_str, size_t name_len, void *old_handle, void **new_handle TSRMLS_DC); - -#endif /* HTTP_PERSISTENT_HANDLE_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/php_http_querystring.c b/php_http_querystring.c new file mode 100644 index 0000000..7304d69 --- /dev/null +++ b/php_http_querystring.c @@ -0,0 +1,729 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +#include +#include + +#ifdef PHP_HTTP_HAVE_ICONV +# undef PHP_ATOM_INC +# include +#endif + +#define QS_MERGE 1 + +static inline void php_http_querystring_set(zval *instance, zval *params, int flags TSRMLS_DC) +{ + zval *qa; + + if (flags & QS_MERGE) { + qa = php_http_zsep(1, IS_ARRAY, zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0 TSRMLS_CC)); + } else { + MAKE_STD_ZVAL(qa); + array_init(qa); + } + + php_http_querystring_update(qa, params, NULL TSRMLS_CC); + zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), qa TSRMLS_CC); + zval_ptr_dtor(&qa); +} + +static inline void php_http_querystring_str(zval *instance, zval *return_value TSRMLS_DC) +{ + zval *qa = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0 TSRMLS_CC); + + if (Z_TYPE_P(qa) == IS_ARRAY) { + php_http_querystring_update(qa, NULL, return_value TSRMLS_CC); + } else { + RETURN_EMPTY_STRING(); + } +} + +static inline void php_http_querystring_get(zval *this_ptr, int type, char *name, uint name_len, zval *defval, zend_bool del, zval *return_value TSRMLS_DC) +{ + zval **arrval, *qarray = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC); + + if ((Z_TYPE_P(qarray) == IS_ARRAY) && (SUCCESS == zend_symtable_find(Z_ARRVAL_P(qarray), name, name_len + 1, (void *) &arrval))) { + if (type) { + zval *value = php_http_ztyp(type, *arrval); + RETVAL_ZVAL(value, 1, 1); + } else { + RETVAL_ZVAL(*arrval, 1, 0); + } + + if (del) { + zval *delarr; + + MAKE_STD_ZVAL(delarr); + array_init(delarr); + add_assoc_null_ex(delarr, name, name_len + 1); + php_http_querystring_set(this_ptr, delarr, QS_MERGE TSRMLS_CC); + zval_ptr_dtor(&delarr); + } + } else if(defval) { + RETURN_ZVAL(defval, 1, 0); + } +} + +#ifdef PHP_HTTP_HAVE_ICONV +STATUS php_http_querystring_xlate(zval *dst, zval *src, const char *ie, const char *oe TSRMLS_DC) +{ + HashPosition pos; + zval **entry = NULL; + char *xlate_str = NULL, *xkey; + size_t xlate_len = 0, xlen; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + + FOREACH_KEYVAL(pos, src, key, entry) { + if (key.type == HASH_KEY_IS_STRING) { + if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.str, key.len-1, &xkey, &xlen, oe, ie)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", key.len-1, key.str, ie, oe); + return FAILURE; + } + } + + if (Z_TYPE_PP(entry) == IS_STRING) { + if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), &xlate_str, &xlate_len, oe, ie)) { + if (key.type == HASH_KEY_IS_STRING) { + efree(xkey); + } + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_PP(entry), Z_STRVAL_PP(entry), ie, oe); + return FAILURE; + } + if (key.type == HASH_KEY_IS_STRING) { + add_assoc_stringl_ex(dst, xkey, xlen+1, xlate_str, xlate_len, 0); + } else { + add_index_stringl(dst, key.num, xlate_str, xlate_len, 0); + } + } else if (Z_TYPE_PP(entry) == IS_ARRAY) { + zval *subarray; + + MAKE_STD_ZVAL(subarray); + array_init(subarray); + if (key.type == HASH_KEY_IS_STRING) { + add_assoc_zval_ex(dst, xkey, xlen+1, subarray); + } else { + add_index_zval(dst, key.num, subarray); + } + if (SUCCESS != php_http_querystring_xlate(subarray, *entry, ie, oe TSRMLS_CC)) { + if (key.type == HASH_KEY_IS_STRING) { + efree(xkey); + } + return FAILURE; + } + } + + if (key.type == HASH_KEY_IS_STRING) { + efree(xkey); + } + } + return SUCCESS; +} +#endif /* HAVE_ICONV */ + +STATUS php_http_querystring_ctor(zval *instance, zval *params TSRMLS_DC) +{ + php_http_querystring_set(instance, params, 0 TSRMLS_CC); + return SUCCESS; +} + +static int apply_querystring(void *pData TSRMLS_DC) +{ + zval **val = pData; + + if (Z_TYPE_PP(val) == IS_ARRAY) { + zval **zvalue; + + if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("value"), (void *) &zvalue)) { + zval *tmp = *val; + + Z_ADDREF_PP(zvalue); + *val = *zvalue; + zval_dtor(tmp); + Z_TYPE_P(tmp) = IS_NULL; + zval_ptr_dtor(&tmp); + } + } + + return ZEND_HASH_APPLY_KEEP; +} + +STATUS php_http_querystring_parse(HashTable *ht, const char *str, size_t len TSRMLS_DC) +{ + STATUS rv = FAILURE; + php_http_params_opts_t opts; + php_http_params_token_t psep = { ZEND_STRL("&") }, *psepp[] = { &psep, NULL }; + php_http_params_token_t vsep = { ZEND_STRL("=") }, *vsepp[] = { &vsep, NULL }; + const char *asi_str = NULL; + size_t asi_len = 0; + + opts.input.str = estrndup(str, len); + opts.input.len = len; + opts.param = psepp; + opts.arg = NULL; + opts.val = vsepp; + opts.flags = PHP_HTTP_PARAMS_QUERY; + + if (SUCCESS == php_http_ini_entry(ZEND_STRL("arg_separator.input"), &asi_str, &asi_len, 0 TSRMLS_CC) && asi_len) { + zval *arr; + + MAKE_STD_ZVAL(arr); + array_init_size(arr, asi_len); + + do { + add_next_index_stringl(arr, asi_str++, 1, 1); + } while (*asi_str); + + opts.param = php_http_params_separator_init(arr TSRMLS_CC); + + zval_ptr_dtor(&arr); + } + + MAKE_STD_ZVAL(opts.defval); + ZVAL_NULL(opts.defval); + + if (php_http_params_parse(ht, &opts TSRMLS_CC)) { + zend_hash_apply(ht, apply_querystring TSRMLS_CC); + rv = SUCCESS; + } + + if (asi_len) { + php_http_params_separator_free(opts.param); + } + + zval_ptr_dtor(&opts.defval); + efree(opts.input.str); + return rv; +} + +STATUS php_http_querystring_update(zval *qarray, zval *params, zval *outstring TSRMLS_DC) +{ + /* enforce proper type */ + if (Z_TYPE_P(qarray) != IS_ARRAY) { + convert_to_array(qarray); + } + + /* modify qarray */ + if (params) { + HashPosition pos; + HashTable *ptr; + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + zval **params_entry, **qarray_entry; + zval zv, *zv_ptr = NULL; + + INIT_PZVAL(&zv); + ZVAL_NULL(&zv); + + /* squeeze the hash out of the zval */ + if (Z_TYPE_P(params) == IS_OBJECT && instanceof_function(Z_OBJCE_P(params), php_http_querystring_class_entry TSRMLS_CC)) { + zv_ptr = php_http_ztyp(IS_ARRAY, zend_read_property(php_http_querystring_class_entry, params, ZEND_STRL("queryArray"), 0 TSRMLS_CC)); + ptr = Z_ARRVAL_P(zv_ptr); + } else if (Z_TYPE_P(params) == IS_OBJECT || Z_TYPE_P(params) == IS_ARRAY) { + ptr = HASH_OF(params); + } else { + zv_ptr = php_http_ztyp(IS_STRING, params); + array_init(&zv); + php_http_querystring_parse(Z_ARRVAL(zv), Z_STRVAL_P(zv_ptr), Z_STRLEN_P(zv_ptr) TSRMLS_CC); + zval_ptr_dtor(&zv_ptr); + zv_ptr = NULL; + ptr = Z_ARRVAL(zv); + } + + FOREACH_HASH_KEYVAL(pos, ptr, key, params_entry) { + /* only public properties */ + if (key.type != HASH_KEY_IS_STRING || *key.str) { + if (Z_TYPE_PP(params_entry) == IS_NULL) { + /* + * delete + */ + if (key.type == HASH_KEY_IS_STRING) { + zend_hash_del(Z_ARRVAL_P(qarray), key.str, key.len); + } else { + zend_hash_index_del(Z_ARRVAL_P(qarray), key.num); + } + } else if ( ((key.type == HASH_KEY_IS_STRING) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), key.str, key.len, (void *) &qarray_entry))) + || ((key.type == HASH_KEY_IS_LONG) && (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(qarray), key.num, (void *) &qarray_entry)))) { + /* + * update + */ + zval equal, *entry = NULL; + + /* recursive */ + if (Z_TYPE_PP(params_entry) == IS_ARRAY || Z_TYPE_PP(params_entry) == IS_OBJECT) { + entry = php_http_zsep(1, IS_ARRAY, *qarray_entry); + php_http_querystring_update(entry, *params_entry, NULL TSRMLS_CC); + } else if ((FAILURE == is_equal_function(&equal, *qarray_entry, *params_entry TSRMLS_CC)) || !Z_BVAL(equal)) { + Z_ADDREF_PP(params_entry); + entry = *params_entry; + } + + if (entry) { + if (key.type == HASH_KEY_IS_STRING) { + zend_hash_update(Z_ARRVAL_P(qarray), key.str, key.len, (void *) &entry, sizeof(zval *), NULL); + } else { + zend_hash_index_update(Z_ARRVAL_P(qarray), key.num, (void *) &entry, sizeof(zval *), NULL); + } + } + } else { + zval *entry; + /* + * add + */ + if (Z_TYPE_PP(params_entry) == IS_OBJECT) { + MAKE_STD_ZVAL(entry); + array_init(entry); + php_http_querystring_update(entry, *params_entry, NULL TSRMLS_CC); + } else { + Z_ADDREF_PP(params_entry); + entry = *params_entry; + } + if (key.type == HASH_KEY_IS_STRING) { + add_assoc_zval_ex(qarray, key.str, key.len, entry); + } else { + add_index_zval(qarray, key.num, entry); + } + } + } + } + /* clean up */ + if (zv_ptr) { + zval_ptr_dtor(&zv_ptr); + } + zval_dtor(&zv); + } + + /* serialize to string */ + if (outstring) { + char *s; + size_t l; + + if (SUCCESS == php_http_url_encode_hash(Z_ARRVAL_P(qarray), NULL, 0, &s, &l TSRMLS_CC)) { + zval_dtor(outstring); + ZVAL_STRINGL(outstring, s, l, 0); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to encode query string"); + return FAILURE; + } + } + + return SUCCESS; +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString___construct, 0, 0, 0) + ZEND_ARG_INFO(0, params) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, __construct) +{ + zval *params = NULL; + zend_error_handling zeh; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", ¶ms), invalid_arg, return); + + zend_replace_error_handling(EH_THROW, php_http_exception_bad_querystring_class_entry, &zeh TSRMLS_CC); + php_http_querystring_set(getThis(), params, 0 TSRMLS_CC); + zend_restore_error_handling(&zeh TSRMLS_CC); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_getGlobalInstance, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, getGlobalInstance) +{ + zval *instance; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + instance = *zend_std_get_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), 0 PHP_HTTP_ZEND_LITERAL_CCN TSRMLS_CC); + + if (Z_TYPE_P(instance) != IS_OBJECT) { + zval **_GET = NULL; + + zend_is_auto_global("_GET", lenof("_GET") TSRMLS_CC); + + if ((SUCCESS == zend_hash_find(&EG(symbol_table), "_GET", sizeof("_GET"), (void *) &_GET)) + && (Z_TYPE_PP(_GET) == IS_ARRAY) + ) { + MAKE_STD_ZVAL(instance); + ZVAL_OBJVAL(instance, php_http_querystring_object_new(php_http_querystring_class_entry TSRMLS_CC), 0); + + SEPARATE_ZVAL_TO_MAKE_IS_REF(_GET); + convert_to_array(*_GET); + zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), *_GET TSRMLS_CC); + + zend_update_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), instance TSRMLS_CC); + zval_ptr_dtor(&instance); + } else { + php_http_throw(unexpected_val, "Could not acquire reference to superglobal GET array", NULL); + } + } + + RETVAL_ZVAL(instance, 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_getIterator, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, getIterator) +{ + zval *retval = NULL, *qa; + + php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return); + + qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC); + + object_init_ex(return_value, spl_ce_RecursiveArrayIterator); + zend_call_method_with_1_params(&return_value, spl_ce_RecursiveArrayIterator, NULL, "__construct", &retval, qa); + if (retval) { + zval_ptr_dtor(&retval); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_toString, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, toString) +{ + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + php_http_querystring_str(getThis(), return_value TSRMLS_CC); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_toArray, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, toArray) +{ + zval *zqa; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + zqa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC); + RETURN_ZVAL(zqa, 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_get, 0, 0, 0) + ZEND_ARG_INFO(0, name) + ZEND_ARG_INFO(0, type) + ZEND_ARG_INFO(0, defval) + ZEND_ARG_INFO(0, delete) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, get) +{ + char *name_str = NULL; + int name_len = 0; + long type = 0; + zend_bool del = 0; + zval *ztype = NULL, *defval = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|szzb", &name_str, &name_len, &ztype, &defval, &del)) { + if (name_str && name_len) { + if (ztype) { + if (Z_TYPE_P(ztype) == IS_LONG) { + type = Z_LVAL_P(ztype); + } else if(Z_TYPE_P(ztype) == IS_STRING) { + switch (Z_STRVAL_P(ztype)[0]) { + case 'B': + case 'b': type = PHP_HTTP_QUERYSTRING_TYPE_BOOL; break; + case 'L': + case 'l': + case 'I': + case 'i': type = PHP_HTTP_QUERYSTRING_TYPE_INT; break; + case 'd': + case 'D': + case 'F': + case 'f': type = PHP_HTTP_QUERYSTRING_TYPE_FLOAT; break; + case 'S': + case 's': type = PHP_HTTP_QUERYSTRING_TYPE_STRING; break; + case 'A': + case 'a': type = PHP_HTTP_QUERYSTRING_TYPE_ARRAY; break; + case 'O': + case 'o': type = PHP_HTTP_QUERYSTRING_TYPE_OBJECT; break; + } + } + } + php_http_querystring_get(getThis(), type, name_str, name_len, defval, del, return_value TSRMLS_CC); + } else { + php_http_querystring_str(getThis(), return_value TSRMLS_CC); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_set, 0, 0, 1) + ZEND_ARG_INFO(0, params) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, set) +{ + zval *params; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶ms)) { + return; + } + + php_http_querystring_set(getThis(), params, QS_MERGE TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_mod, 0, 0, 0) + ZEND_ARG_INFO(0, params) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, mod) +{ + zval *params; + zend_error_handling zeh; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶ms), invalid_arg, return); + + zend_replace_error_handling(EH_THROW, php_http_exception_bad_querystring_class_entry, &zeh TSRMLS_CC); + ZVAL_OBJVAL(return_value, Z_OBJ_HT_P(getThis())->clone_obj(getThis() TSRMLS_CC), 0); + php_http_querystring_set(return_value, params, QS_MERGE TSRMLS_CC); + zend_restore_error_handling(&zeh TSRMLS_CC); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString___getter, 0, 0, 1) + ZEND_ARG_INFO(0, name) + ZEND_ARG_INFO(0, defval) + ZEND_ARG_INFO(0, delete) +ZEND_END_ARG_INFO(); +#define PHP_HTTP_QUERYSTRING_GETTER(method, TYPE) \ +PHP_METHOD(HttpQueryString, method) \ +{ \ + char *name; \ + int name_len; \ + zval *defval = NULL; \ + zend_bool del = 0; \ + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zb", &name, &name_len, &defval, &del)) { \ + php_http_querystring_get(getThis(), TYPE, name, name_len, defval, del, return_value TSRMLS_CC); \ + } \ +} +PHP_HTTP_QUERYSTRING_GETTER(getBool, IS_BOOL); +PHP_HTTP_QUERYSTRING_GETTER(getInt, IS_LONG); +PHP_HTTP_QUERYSTRING_GETTER(getFloat, IS_DOUBLE); +PHP_HTTP_QUERYSTRING_GETTER(getString, IS_STRING); +PHP_HTTP_QUERYSTRING_GETTER(getArray, IS_ARRAY); +PHP_HTTP_QUERYSTRING_GETTER(getObject, IS_OBJECT); + +#ifdef PHP_HTTP_HAVE_ICONV +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_xlate, 0, 0, 2) + ZEND_ARG_INFO(0, from_encoding) + ZEND_ARG_INFO(0, to_encoding) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, xlate) +{ + char *ie, *oe; + int ie_len, oe_len; + zval *na, *qa; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &ie, &ie_len, &oe, &oe_len), invalid_arg, return); + + MAKE_STD_ZVAL(na); + array_init(na); + qa = php_http_ztyp(IS_ARRAY, zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC)); + + php_http_expect(SUCCESS == php_http_querystring_xlate(na, qa, ie, oe TSRMLS_CC), bad_conversion, + zval_ptr_dtor(&na); + zval_ptr_dtor(&qa); + return; + ); + + php_http_querystring_set(getThis(), na, 0 TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); + + zval_ptr_dtor(&na); + zval_ptr_dtor(&qa); +} +#endif /* HAVE_ICONV */ + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_serialize, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, serialize) +{ + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + php_http_querystring_str(getThis(), return_value TSRMLS_CC); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_unserialize, 0, 0, 1) + ZEND_ARG_INFO(0, serialized) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, unserialize) +{ + zval *serialized; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &serialized)) { + return; + } + + if (Z_TYPE_P(serialized) == IS_STRING) { + php_http_querystring_set(getThis(), serialized, 0 TSRMLS_CC); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected a string as parameter"); + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, offsetGet) +{ + char *offset_str; + int offset_len; + zval **value, *qa; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) { + return; + } + + qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC); + + if (Z_TYPE_P(qa) == IS_ARRAY) { + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(qa), offset_str, offset_len + 1, (void *) &value)) { + RETVAL_ZVAL(*value, 1, 0); + } + } +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, offsetSet) +{ + char *offset_str; + int offset_len; + zval *value, *param; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &offset_str, &offset_len, &value)) { + return; + } + + MAKE_STD_ZVAL(param); + array_init(param); + Z_ADDREF_P(value); + add_assoc_zval_ex(param, offset_str, offset_len + 1, value); + php_http_querystring_set(getThis(), param, 0 TSRMLS_CC); + zval_ptr_dtor(¶m); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_offsetExists, 0, 0, 1) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, offsetExists) +{ + char *offset_str; + int offset_len; + zval **value, *qa; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) { + return; + } + + qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC); + + if (Z_TYPE_P(qa) == IS_ARRAY) { + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(qa), offset_str, offset_len + 1, (void *) &value)) { + RETURN_BOOL(Z_TYPE_PP(value) != IS_NULL); + } + } + RETURN_FALSE; +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_offsetUnset, 0, 0, 1) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpQueryString, offsetUnset) +{ + char *offset_str; + int offset_len; + zval *param; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) { + return; + } + + MAKE_STD_ZVAL(param); + array_init(param); + add_assoc_null_ex(param, offset_str, offset_len + 1); + php_http_querystring_set(getThis(), param, QS_MERGE TSRMLS_CC); + zval_ptr_dtor(¶m); +} + +zend_class_entry *php_http_querystring_class_entry; + +static zend_function_entry php_http_querystring_methods[] = { + PHP_ME(HttpQueryString, __construct, ai_HttpQueryString___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL) + + PHP_ME(HttpQueryString, toArray, ai_HttpQueryString_toArray, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, toString, ai_HttpQueryString_toString, ZEND_ACC_PUBLIC) + ZEND_MALIAS(HttpQueryString, __toString, toString, ai_HttpQueryString_toString, ZEND_ACC_PUBLIC) + + PHP_ME(HttpQueryString, get, ai_HttpQueryString_get, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, set, ai_HttpQueryString_set, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, mod, ai_HttpQueryString_mod, ZEND_ACC_PUBLIC) + + PHP_ME(HttpQueryString, getBool, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, getInt, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, getFloat, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, getString, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, getArray, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, getObject, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC) + + PHP_ME(HttpQueryString, getIterator, ai_HttpQueryString_getIterator, ZEND_ACC_PUBLIC) + + PHP_ME(HttpQueryString, getGlobalInstance, ai_HttpQueryString_getGlobalInstance, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) +#ifdef PHP_HTTP_HAVE_ICONV + PHP_ME(HttpQueryString, xlate, ai_HttpQueryString_xlate, ZEND_ACC_PUBLIC) +#endif + + /* Implements Serializable */ + PHP_ME(HttpQueryString, serialize, ai_HttpQueryString_serialize, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, unserialize, ai_HttpQueryString_unserialize, ZEND_ACC_PUBLIC) + + /* Implements ArrayAccess */ + PHP_ME(HttpQueryString, offsetGet, ai_HttpQueryString_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, offsetSet, ai_HttpQueryString_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, offsetExists, ai_HttpQueryString_offsetExists, ZEND_ACC_PUBLIC) + PHP_ME(HttpQueryString, offsetUnset, ai_HttpQueryString_offsetUnset, ZEND_ACC_PUBLIC) + + EMPTY_FUNCTION_ENTRY +}; + +PHP_MINIT_FUNCTION(http_querystring) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "QueryString", php_http_querystring_methods); + php_http_querystring_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + php_http_querystring_class_entry->create_object = php_http_querystring_object_new; + zend_class_implements(php_http_querystring_class_entry TSRMLS_CC, 3, zend_ce_serializable, zend_ce_arrayaccess, zend_ce_aggregate); + + zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); + zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("queryArray"), ZEND_ACC_PRIVATE TSRMLS_CC); + + zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_BOOL"), PHP_HTTP_QUERYSTRING_TYPE_BOOL TSRMLS_CC); + zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_INT"), PHP_HTTP_QUERYSTRING_TYPE_INT TSRMLS_CC); + zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_FLOAT"), PHP_HTTP_QUERYSTRING_TYPE_FLOAT TSRMLS_CC); + zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_STRING"), PHP_HTTP_QUERYSTRING_TYPE_STRING TSRMLS_CC); + zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_ARRAY"), PHP_HTTP_QUERYSTRING_TYPE_ARRAY TSRMLS_CC); + zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_OBJECT"), PHP_HTTP_QUERYSTRING_TYPE_OBJECT TSRMLS_CC); + + return SUCCESS; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_querystring.h b/php_http_querystring.h new file mode 100644 index 0000000..6418f83 --- /dev/null +++ b/php_http_querystring.h @@ -0,0 +1,47 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_QUERYSTRING_H +#define PHP_HTTP_QUERYSTRING_H + +#ifdef PHP_HTTP_HAVE_ICONV +PHP_HTTP_API STATUS php_http_querystring_xlate(zval *dst, zval *src, const char *ie, const char *oe TSRMLS_DC); +#endif /* PHP_HTTP_HAVE_ICONV */ +PHP_HTTP_API STATUS php_http_querystring_update(zval *qarray, zval *params, zval *qstring TSRMLS_DC); +PHP_HTTP_API STATUS php_http_querystring_ctor(zval *instance, zval *params TSRMLS_DC); + +typedef php_http_object_t php_http_querystring_object_t; + +#define PHP_HTTP_QUERYSTRING_TYPE_BOOL IS_BOOL +#define PHP_HTTP_QUERYSTRING_TYPE_INT IS_LONG +#define PHP_HTTP_QUERYSTRING_TYPE_FLOAT IS_DOUBLE +#define PHP_HTTP_QUERYSTRING_TYPE_STRING IS_STRING +#define PHP_HTTP_QUERYSTRING_TYPE_ARRAY IS_ARRAY +#define PHP_HTTP_QUERYSTRING_TYPE_OBJECT IS_OBJECT + +PHP_HTTP_API zend_class_entry *php_http_querystring_class_entry; + +PHP_MINIT_FUNCTION(http_querystring); + +#define php_http_querystring_object_new php_http_object_new +#define php_http_querystring_object_new_ex php_http_object_new_ex + +#endif /* PHP_HTTP_QUERYSTRING_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_querystring_object.h b/php_http_querystring_object.h deleted file mode 100644 index 1b6f2be..0000000 --- a/php_http_querystring_object.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_QUERYSTRING_OBJECT_H -#define PHP_HTTP_QUERYSTRING_OBJECT_H -#ifdef ZEND_ENGINE_2 - -typedef struct _http_querystring_object_t { - zend_object zo; -} http_querystring_object; - -#define HTTP_QUERYSTRING_TYPE_BOOL IS_BOOL -#define HTTP_QUERYSTRING_TYPE_INT IS_LONG -#define HTTP_QUERYSTRING_TYPE_FLOAT IS_DOUBLE -#define HTTP_QUERYSTRING_TYPE_STRING IS_STRING -#define HTTP_QUERYSTRING_TYPE_ARRAY IS_ARRAY -#define HTTP_QUERYSTRING_TYPE_OBJECT IS_OBJECT - -extern zend_class_entry *http_querystring_object_ce; -extern zend_function_entry http_querystring_object_fe[]; - -extern PHP_MINIT_FUNCTION(http_querystring_object); - -#define http_querystring_object_new(ce) _http_querystring_object_new((ce) TSRMLS_CC) -extern zend_object_value _http_querystring_object_new(zend_class_entry *ce TSRMLS_DC); -#define http_querystring_object_new_ex(ce, n, ptr) _http_querystring_object_new_ex((ce), (n), (ptr) TSRMLS_CC) -extern zend_object_value _http_querystring_object_new_ex(zend_class_entry *ce, void *nothing, http_querystring_object **ptr TSRMLS_DC); -#define http_querystring_object_free(o) _http_querystring_object_free((o) TSRMLS_CC) -extern void _http_querystring_object_free(zend_object *object TSRMLS_DC); - -PHP_METHOD(HttpQueryString, __construct); -PHP_METHOD(HttpQueryString, toString); -PHP_METHOD(HttpQueryString, toArray); -PHP_METHOD(HttpQueryString, get); -PHP_METHOD(HttpQueryString, set); -PHP_METHOD(HttpQueryString, mod); -PHP_METHOD(HttpQueryString, getBool); -PHP_METHOD(HttpQueryString, getInt); -PHP_METHOD(HttpQueryString, getFloat); -PHP_METHOD(HttpQueryString, getString); -PHP_METHOD(HttpQueryString, getArray); -PHP_METHOD(HttpQueryString, getObject); -#ifdef HTTP_HAVE_ICONV -PHP_METHOD(HttpQueryString, xlate); -#endif -PHP_METHOD(HttpQueryString, factory); -#ifndef WONKY -PHP_METHOD(HttpQueryString, singleton); -#endif -PHP_METHOD(HttpQueryString, serialize); -PHP_METHOD(HttpQueryString, unserialize); -PHP_METHOD(HttpQueryString, offsetGet); -PHP_METHOD(HttpQueryString, offsetSet); -PHP_METHOD(HttpQueryString, offsetExists); -PHP_METHOD(HttpQueryString, offsetUnset); -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_request_api.h b/php_http_request_api.h deleted file mode 100644 index bebceae..0000000 --- a/php_http_request_api.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_REQUEST_API_H -#define PHP_HTTP_REQUEST_API_H - -#ifdef HTTP_HAVE_CURL - -#include "php_http_request_body_api.h" -#include "php_http_request_method_api.h" - -extern PHP_MINIT_FUNCTION(http_request); -extern PHP_MSHUTDOWN_FUNCTION(http_request); - -typedef struct _http_request_t { - CURL *ch; - char *url; - http_request_method meth; - http_request_body *body; - - struct { - curl_infotype last_type; - phpstr request; - phpstr response; - } conv; - - struct { - phpstr cookies; - HashTable options; - struct curl_slist *headers; - } _cache; - - struct { - uint count; - double delay; - } _retry; - - char _error[CURL_ERROR_SIZE+1]; - zval *_progress_callback; - -#ifdef ZTS - void ***tsrm_ls; -#endif - - uint _in_progress_cb:1; - -} http_request; - -#ifndef pestrndup -# define pestrndup(s,l,p) _pestrndup((s),(l),(p)) -static inline void *_pestrndup(const void *s, size_t l, int p) -{ - void *d = pemalloc(l+1, p); - memcpy(d, s, l); - ((char *) d)[l] = '\0'; - return d; -} -#endif - -/* CURLOPT_PRIVATE storage living as long as a CURL handle */ -typedef struct _http_request_storage_t { - char *url; - char *cookiestore; - char errorbuffer[CURL_ERROR_SIZE]; -} http_request_storage; - -static inline http_request_storage *http_request_storage_get(CURL *ch) -{ - http_request_storage *st = NULL; - curl_easy_getinfo(ch, CURLINFO_PRIVATE, &st); - return st; -} - -#define http_curl_init(r) http_curl_init_ex(NULL, (r)) -#define http_curl_init_ex(c, r) _http_curl_init_ex((c), (r) TSRMLS_CC) -PHP_HTTP_API CURL *_http_curl_init_ex(CURL *ch, http_request *request TSRMLS_DC); - -#define http_curl_free(c) _http_curl_free((c) TSRMLS_CC) -PHP_HTTP_API void _http_curl_free(CURL **ch TSRMLS_DC); - -#define http_curl_copy(c) _http_curl_copy((c) TSRMLS_CC) -PHP_HTTP_API CURL *_http_curl_copy(CURL *ch TSRMLS_DC); - -#define http_request_new() _http_request_init_ex(NULL, NULL, 0, NULL ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -#define http_request_init(r) _http_request_init_ex((r), NULL, 0, NULL ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -#define http_request_init_ex(r, c, m, u) _http_request_init_ex((r), (c), (m), (u) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API http_request *_http_request_init_ex(http_request *request, CURL *ch, http_request_method meth, const char *url ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); - -#define http_request_dtor(r) _http_request_dtor((r)) -PHP_HTTP_API void _http_request_dtor(http_request *request); - -#define http_request_free(r) _http_request_free((r)) -PHP_HTTP_API void _http_request_free(http_request **request); - -#define http_request_reset(r) _http_request_reset(r) -PHP_HTTP_API void _http_request_reset(http_request *r); - -#define http_request_enable_cookies(r) _http_request_enable_cookies(r) -PHP_HTTP_API STATUS _http_request_enable_cookies(http_request *request); - -#define http_request_reset_cookies(r, s) _http_request_reset_cookies((r), (s)) -PHP_HTTP_API STATUS _http_request_reset_cookies(http_request *request, int session_only); - -#define http_request_flush_cookies(r) _http_request_flush_cookies(r) -PHP_HTTP_API STATUS _http_request_flush_cookies(http_request *request); - -#define http_request_defaults(r) _http_request_defaults(r) -PHP_HTTP_API void _http_request_defaults(http_request *request); - -#define http_request_prepare(r, o) _http_request_prepare((r), (o)) -PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *options); - -#define http_request_exec(r) _http_request_exec((r)) -PHP_HTTP_API void _http_request_exec(http_request *request); - -#define http_request_info(r, i) _http_request_info((r), (i)) -PHP_HTTP_API void _http_request_info(http_request *request, HashTable *info); - -#define http_request_set_progress_callback(r, cb) _http_request_set_progress_callback((r), (cb)) -PHP_HTTP_API void _http_request_set_progress_callback(http_request *request, zval *cb); - -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_request_body_api.h b/php_http_request_body_api.h deleted file mode 100644 index 8d65e59..0000000 --- a/php_http_request_body_api.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_REQUEST_BODY_API_H -#define PHP_HTTP_REQUEST_BODY_API_H - -#ifdef HTTP_HAVE_CURL - -#define HTTP_REQUEST_BODY_EMPTY 0 -#define HTTP_REQUEST_BODY_CSTRING 1 -#define HTTP_REQUEST_BODY_CURLPOST 2 -#define HTTP_REQUEST_BODY_UPLOADFILE 3 -typedef struct _http_request_body_t { - void *data; - size_t size; - uint type:3; - uint free:1; - uint priv:28; -} http_request_body; - - -#define http_request_body_new() http_request_body_init(NULL) -#define http_request_body_init(b) http_request_body_init_ex((b), 0, NULL, 0, 0) -#define http_request_body_init_ex(b, t, d, l, f) _http_request_body_init_ex((b), (t), (d), (l), (f) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -#define http_request_body_init_rel(b, t, d, l, f) _http_request_body_init_ex((b), (t), (d), (l), (f) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC TSRMLS_CC) -PHP_HTTP_API http_request_body *_http_request_body_init_ex(http_request_body *body, int type, void *data, size_t len, zend_bool free ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); - -#define http_request_body_fill(b, fields, files) _http_request_body_fill((b), (fields), (files) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC) -PHP_HTTP_API http_request_body *_http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC); - -#define http_request_body_encode(b, s, l) _http_request_body_encode((b), (s), (l) TSRMLS_CC) -PHP_HTTP_API STATUS _http_request_body_encode(http_request_body *body, char **buf, size_t *len TSRMLS_DC); - -#define http_request_body_dtor(b) _http_request_body_dtor((b) TSRMLS_CC) -PHP_HTTP_API void _http_request_body_dtor(http_request_body *body TSRMLS_DC); - -#define http_request_body_free(b) _http_request_body_free((b) TSRMLS_CC) -PHP_HTTP_API void _http_request_body_free(http_request_body **body TSRMLS_DC); - -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_request_datashare_api.h b/php_http_request_datashare_api.h deleted file mode 100644 index 15818b0..0000000 --- a/php_http_request_datashare_api.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_REQUEST_DATASHARE_API_H -#define PHP_HTTP_REQUEST_DATASHARE_API_H -#ifdef HTTP_HAVE_CURL -#ifdef ZEND_ENGINE_2 - -#ifdef ZTS -typedef struct _http_request_datashare_lock_t { - CURL *ch; - MUTEX_T mx; -} http_request_datashare_lock; - -typedef union _http_request_datashare_handle_t { - zend_llist *list; - http_request_datashare_lock *locks; -} http_request_datashare_handle; -#else -typedef struct _http_request_datashare_handle_t { - zend_llist *list; -} http_request_datashare_handle; -#endif - -typedef struct _http_request_datashare_t { - CURLSH *ch; - zend_bool persistent; - http_request_datashare_handle handle; -} http_request_datashare; - -#define HTTP_RSHARE_HANDLES(s) ((s)->persistent ? &HTTP_G->request.datashare.handles : (s)->handle.list) - -#define http_request_datashare_global_get _http_request_datashare_global_get -extern http_request_datashare *_http_request_datashare_global_get(void); - -extern PHP_MINIT_FUNCTION(http_request_datashare); -extern PHP_MSHUTDOWN_FUNCTION(http_request_datashare); -extern PHP_RINIT_FUNCTION(http_request_datashare); -extern PHP_RSHUTDOWN_FUNCTION(http_request_datashare); - -#define http_request_datashare_new() _http_request_datashare_init_ex(NULL, 0 TSRMLS_CC) -#define http_request_datashare_init(s) _http_request_datashare_init_ex((s), 0 TSRMLS_CC) -#define http_request_datashare_init_ex(s, p) _http_request_datashare_init_ex((s), (p) TSRMLS_CC) -PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC); - -#define http_request_datashare_attach(s, r) _http_request_datashare_attach((s), (r) TSRMLS_CC) -PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC); - -#define http_request_datashare_detach(s, r) _http_request_datashare_detach((s), (r) TSRMLS_CC) -PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC); - -#define http_request_datashare_detach_all(s) _http_request_datashare_detach_all((s) TSRMLS_CC) -PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC); - -#define http_request_datashare_dtor(s) _http_request_datashare_dtor((s) TSRMLS_CC) -PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC); - -#define http_request_datashare_free(s) _http_request_datashare_free((s) TSRMLS_CC) -PHP_HTTP_API void _http_request_datashare_free(http_request_datashare **share TSRMLS_DC); - -#define http_request_datashare_set(s, o, l, e) _http_request_datashare_set((s), (o), (l), (e) TSRMLS_CC) -PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC); - - -#endif -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_request_int.h b/php_http_request_int.h deleted file mode 100644 index ff220ca..0000000 --- a/php_http_request_int.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#if defined(ZTS) && defined(HTTP_HAVE_SSL) -# ifdef PHP_WIN32 -# define HTTP_NEED_OPENSSL_TSL -# include -# else /* !PHP_WIN32 */ -# if defined(HTTP_HAVE_OPENSSL) -# define HTTP_NEED_OPENSSL_TSL -# include -# elif defined(HTTP_HAVE_GNUTLS) -# define HTTP_NEED_GNUTLS_TSL -# include -# else -# warning \ - "libcurl was compiled with SSL support, but configure could not determine which" \ - "library was used; thus no SSL crypto locking callbacks will be set, which may " \ - "cause random crashes on SSL requests" -# endif /* HTTP_HAVE_OPENSSL || HTTP_HAVE_GNUTLS */ -# endif /* PHP_WIN32 */ -#endif /* ZTS && HTTP_HAVE_SSL */ - -#define HTTP_CURL_OPT(OPTION, p) curl_easy_setopt((request->ch), OPTION, (p)) - -#define HTTP_CURL_OPT_STRING(OPTION, ldiff, obdc) \ - { \ - char *K = #OPTION; \ - HTTP_CURL_OPT_STRING_EX(K+lenof("CURLOPT_KEY")+ldiff, OPTION, obdc); \ - } -#define HTTP_CURL_OPT_STRING_EX(keyname, optname, obdc) \ - if (!strcasecmp(key.str, keyname)) { \ - zval *copy = http_request_option_cache_ex(request, keyname, strlen(keyname)+1, 0, http_zsep(IS_STRING, *param)); \ - if (obdc) { \ - HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(copy), return FAILURE); \ - } \ - HTTP_CURL_OPT(optname, Z_STRVAL_P(copy)); \ - zval_ptr_dtor(©); \ - continue; \ - } -#define HTTP_CURL_OPT_LONG(OPTION, ldiff) \ - { \ - char *K = #OPTION; \ - HTTP_CURL_OPT_LONG_EX(K+lenof("CURLOPT_KEY")+ldiff, OPTION); \ - } -#define HTTP_CURL_OPT_LONG_EX(keyname, optname) \ - if (!strcasecmp(key.str, keyname)) { \ - zval *copy = http_zsep(IS_LONG, *param); \ - HTTP_CURL_OPT(optname, Z_LVAL_P(copy)); \ - zval_ptr_dtor(©); \ - continue; \ - } - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/php_http_request_method_api.h b/php_http_request_method_api.h deleted file mode 100644 index 98787b6..0000000 --- a/php_http_request_method_api.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_REQUEST_METHOD_API_H -#define PHP_HTTP_REQUEST_METHOD_API_H - -typedef enum _http_request_method_t { - /* force the enum to be signed */ - HTTP_NEG_REQUEST_METHOD =-1, - HTTP_NO_REQUEST_METHOD = 0, - /* HTTP/1.1 */ - HTTP_GET = 1, - HTTP_HEAD = 2, - HTTP_POST = 3, - HTTP_PUT = 4, - HTTP_DELETE = 5, - HTTP_OPTIONS = 6, - HTTP_TRACE = 7, - HTTP_CONNECT = 8, - /* WebDAV - RFC 2518 */ - HTTP_PROPFIND = 9, - HTTP_PROPPATCH = 10, - HTTP_MKCOL = 11, - HTTP_COPY = 12, - HTTP_MOVE = 13, - HTTP_LOCK = 14, - HTTP_UNLOCK = 15, - /* WebDAV Versioning - RFC 3253 */ - HTTP_VERSION_CONTROL = 16, - HTTP_REPORT = 17, - HTTP_CHECKOUT = 18, - HTTP_CHECKIN = 19, - HTTP_UNCHECKOUT = 20, - HTTP_MKWORKSPACE = 21, - HTTP_UPDATE = 22, - HTTP_LABEL = 23, - HTTP_MERGE = 24, - HTTP_BASELINE_CONTROL = 25, - HTTP_MKACTIVITY = 26, - /* WebDAV Access Control - RFC 3744 */ - HTTP_ACL = 27, - HTTP_MAX_REQUEST_METHOD = 28 -} http_request_method; - -#define HTTP_MIN_REQUEST_METHOD (HTTP_NO_REQUEST_METHOD + 1) -#define HTTP_STD_REQUEST_METHOD(m) ((m > HTTP_NO_REQUEST_METHOD) && (m < HTTP_MAX_REQUEST_METHOD)) - -extern PHP_MINIT_FUNCTION(http_request_method); -extern PHP_RINIT_FUNCTION(http_request_method); -extern PHP_RSHUTDOWN_FUNCTION(http_request_method); - -#define http_request_method_name(m) _http_request_method_name((m) TSRMLS_CC) -PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC); - -#define http_request_method_exists(u, l, c) _http_request_method_exists((u), (l), (c) TSRMLS_CC) -PHP_HTTP_API int _http_request_method_exists(int by_name, http_request_method id, const char *name TSRMLS_DC); - -#define http_request_method_register(m, l) _http_request_method_register((m), (l) TSRMLS_CC) -PHP_HTTP_API int _http_request_method_register(const char *method, int method_name_len TSRMLS_DC); - -#define http_request_method_unregister(mn) _http_request_method_unregister((mn) TSRMLS_CC) -PHP_HTTP_API STATUS _http_request_method_unregister(int method TSRMLS_DC); - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_request_object.h b/php_http_request_object.h deleted file mode 100644 index 262a202..0000000 --- a/php_http_request_object.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_REQUEST_OBJECT_H -#define PHP_HTTP_REQUEST_OBJECT_H -#ifdef HTTP_HAVE_CURL -#ifdef ZEND_ENGINE_2 - -#include "php_http_request_api.h" -#include "php_http_request_pool_api.h" -#include "php_http_request_datashare_api.h" - -typedef struct _http_request_object_t { - zend_object zo; - http_request *request; - http_request_pool *pool; - http_request_datashare *share; -} http_request_object; - -extern zend_class_entry *http_request_object_ce; -extern zend_function_entry http_request_object_fe[]; - -extern PHP_MINIT_FUNCTION(http_request_object); - -#define http_request_object_new(ce) _http_request_object_new((ce) TSRMLS_CC) -extern zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC); -#define http_request_object_new_ex(ce, ch, ptr) _http_request_object_new_ex((ce), (ch), (ptr) TSRMLS_CC) -extern zend_object_value _http_request_object_new_ex(zend_class_entry *ce, CURL *ch, http_request_object **ptr TSRMLS_DC); -#define http_request_object_clone(zv) _http_request_object_clone_obj((zv) TSRMLS_CC) -extern zend_object_value _http_request_object_clone_obj(zval *zobject TSRMLS_DC); -#define http_request_object_free(o) _http_request_object_free((o) TSRMLS_CC) -extern void _http_request_object_free(zend_object *object TSRMLS_DC); - -#define http_request_object_requesthandler(req, this) _http_request_object_requesthandler((req), (this) TSRMLS_CC) -extern STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr TSRMLS_DC); -#define http_request_object_responsehandler(req, this) _http_request_object_responsehandler((req), (this) TSRMLS_CC) -extern STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this_ptr TSRMLS_DC); - -PHP_METHOD(HttpRequest, __construct); -PHP_METHOD(HttpRequest, setOptions); -PHP_METHOD(HttpRequest, getOptions); -PHP_METHOD(HttpRequest, addSslOptions); -PHP_METHOD(HttpRequest, setSslOptions); -PHP_METHOD(HttpRequest, getSslOptions); -PHP_METHOD(HttpRequest, addHeaders); -PHP_METHOD(HttpRequest, getHeaders); -PHP_METHOD(HttpRequest, setHeaders); -PHP_METHOD(HttpRequest, addCookies); -PHP_METHOD(HttpRequest, getCookies); -PHP_METHOD(HttpRequest, setCookies); -PHP_METHOD(HttpRequest, enableCookies); -PHP_METHOD(HttpRequest, resetCookies); -PHP_METHOD(HttpRequest, flushCookies); -PHP_METHOD(HttpRequest, setMethod); -PHP_METHOD(HttpRequest, getMethod); -PHP_METHOD(HttpRequest, setUrl); -PHP_METHOD(HttpRequest, getUrl); -PHP_METHOD(HttpRequest, setContentType); -PHP_METHOD(HttpRequest, getContentType); -PHP_METHOD(HttpRequest, setQueryData); -PHP_METHOD(HttpRequest, getQueryData); -PHP_METHOD(HttpRequest, addQueryData); -PHP_METHOD(HttpRequest, setPostFields); -PHP_METHOD(HttpRequest, getPostFields); -PHP_METHOD(HttpRequest, addPostFields); -PHP_METHOD(HttpRequest, getBody); -PHP_METHOD(HttpRequest, setBody); -PHP_METHOD(HttpRequest, addBody); -PHP_METHOD(HttpRequest, addPostFile); -PHP_METHOD(HttpRequest, setPostFiles); -PHP_METHOD(HttpRequest, getPostFiles); -PHP_METHOD(HttpRequest, setPutFile); -PHP_METHOD(HttpRequest, getPutFile); -PHP_METHOD(HttpRequest, getPutData); -PHP_METHOD(HttpRequest, setPutData); -PHP_METHOD(HttpRequest, addPutData); -PHP_METHOD(HttpRequest, send); -PHP_METHOD(HttpRequest, getResponseData); -PHP_METHOD(HttpRequest, getResponseHeader); -PHP_METHOD(HttpRequest, getResponseCookies); -PHP_METHOD(HttpRequest, getResponseCode); -PHP_METHOD(HttpRequest, getResponseStatus); -PHP_METHOD(HttpRequest, getResponseBody); -PHP_METHOD(HttpRequest, getResponseInfo); -PHP_METHOD(HttpRequest, getResponseMessage); -PHP_METHOD(HttpRequest, getRawResponseMessage); -PHP_METHOD(HttpRequest, getRequestMessage); -PHP_METHOD(HttpRequest, getRawRequestMessage); -PHP_METHOD(HttpRequest, getHistory); -PHP_METHOD(HttpRequest, clearHistory); -PHP_METHOD(HttpRequest, getMessageClass); -PHP_METHOD(HttpRequest, setMessageClass); -PHP_METHOD(HttpRequest, factory); - -#endif -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_request_pool_api.h b/php_http_request_pool_api.h deleted file mode 100644 index c5fe971..0000000 --- a/php_http_request_pool_api.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_REQUEST_POOL_API_H -#define PHP_HTTP_REQUEST_POOL_API_H -#ifdef HTTP_HAVE_CURL -#ifdef ZEND_ENGINE_2 - -typedef struct _http_request_pool_t { - CURLM *ch; - zend_llist finished; - zend_llist handles; - int unfinished; -#ifdef ZTS - void ***tsrm_ls; -#endif -#ifdef HTTP_HAVE_EVENT - struct event *timeout; - unsigned useevents:1; - unsigned runsocket:1; -#endif -} http_request_pool; - -typedef int (*http_request_pool_apply_func)(http_request_pool *pool, zval *request); -typedef int (*http_request_pool_apply_with_arg_func)(http_request_pool *pool, zval *request, void *arg); - -PHP_MINIT_FUNCTION(http_request_pool); -#ifdef HTTP_HAVE_EVENT -PHP_RINIT_FUNCTION(http_request_pool); -#endif - -#define http_request_pool_timeout _http_request_pool_timeout -extern struct timeval *_http_request_pool_timeout(http_request_pool *pool, struct timeval *timeout); - -#define http_request_pool_responsehandler _http_request_pool_responsehandler -extern void _http_request_pool_responsehandler(http_request_pool *pool); - -#define http_request_pool_apply_responsehandler _http_request_pool_responsehandler -extern int _http_request_pool_apply_responsehandler(http_request_pool *pool, zval *req, void *ch); - -#define http_request_pool_init(p) _http_request_pool_init((p) TSRMLS_CC) -PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC); - -#define http_request_pool_attach(p, r) _http_request_pool_attach((p), (r)) -PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request); - -#define http_request_pool_detach(p, r) _http_request_pool_detach((p), (r)) -PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request); - -#define http_request_pool_apply(p, f) _http_request_pool_apply((p), (f)) -PHP_HTTP_API void _http_request_pool_apply(http_request_pool *pool, http_request_pool_apply_func cb); - -#define http_request_pool_apply_with_arg(p, f, a) _http_request_pool_apply_with_arg((p), (f), (a)) -PHP_HTTP_API void _http_request_pool_apply_with_arg(http_request_pool *pool, http_request_pool_apply_with_arg_func cb, void *arg); - -#define http_request_pool_detach_all(p) _http_request_pool_detach_all((p)) -PHP_HTTP_API void _http_request_pool_detach_all(http_request_pool *pool); - -#define http_request_pool_send(p) _http_request_pool_send((p)) -PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool); - -#define http_request_pool_select _http_request_pool_select -PHP_HTTP_API STATUS _http_request_pool_select(http_request_pool *pool); - -#define http_request_pool_select_ex _http_request_pool_select_ex -PHP_HTTP_API STATUS _http_request_pool_select_ex(http_request_pool *pool, struct timeval *custom_timeout); - -#define http_request_pool_perform(p) _http_request_pool_perform((p)) -PHP_HTTP_API int _http_request_pool_perform(http_request_pool *pool); - -#define http_request_pool_dtor(p) _http_request_pool_dtor((p)) -PHP_HTTP_API void _http_request_pool_dtor(http_request_pool *pool); - -#endif -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_requestdatashare_object.h b/php_http_requestdatashare_object.h deleted file mode 100644 index d19248e..0000000 --- a/php_http_requestdatashare_object.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_REQUEST_DATASHARE_OBJECT_H -#define PHP_HTTP_REQUEST_DATASHARE_OBJECT_H -#ifdef HTTP_HAVE_CURL -#ifdef ZEND_ENGINE_2 - -typedef struct _http_requestdatashare_object_t { - zend_object zo; - http_request_datashare *share; -} http_requestdatashare_object; - -extern zend_class_entry *http_requestdatashare_object_ce; -extern zend_function_entry http_requestdatashare_object_fe[]; - -extern PHP_MINIT_FUNCTION(http_requestdatashare_object); - -#define http_requestdatashare_object_new(ce) _http_requestdatashare_object_new((ce) TSRMLS_CC) -extern zend_object_value _http_requestdatashare_object_new(zend_class_entry *ce TSRMLS_DC); -#define http_requestdatashare_object_new_ex(ce, s, ptr) _http_requestdatashare_object_new_ex((ce), (s), (ptr) TSRMLS_CC) -extern zend_object_value _http_requestdatashare_object_new_ex(zend_class_entry *ce, http_request_datashare *share, http_requestdatashare_object **ptr TSRMLS_DC); -#define http_requestdatashare_object_free(o) _http_requestdatashare_object_free((o) TSRMLS_CC) -extern void _http_requestdatashare_object_free(zend_object *object TSRMLS_DC); - -PHP_METHOD(HttpRequestDataShare, __destruct); -PHP_METHOD(HttpRequestDataShare, count); -PHP_METHOD(HttpRequestDataShare, attach); -PHP_METHOD(HttpRequestDataShare, detach); -PHP_METHOD(HttpRequestDataShare, reset); -PHP_METHOD(HttpRequestDataShare, factory); -#ifndef WONKY -PHP_METHOD(HttpRequestDataShare, singleton); -#endif - -#endif -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_requestpool_object.h b/php_http_requestpool_object.h deleted file mode 100644 index 51a1dcc..0000000 --- a/php_http_requestpool_object.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_REQUESTPOOL_OBJECT_H -#define PHP_HTTP_REQUESTPOOL_OBJECT_H -#ifdef HTTP_HAVE_CURL -#ifdef ZEND_ENGINE_2 - -typedef struct _http_requestpool_object_t { - zend_object zo; - http_request_pool pool; - struct { - long pos; - } iterator; -} http_requestpool_object; - -extern zend_class_entry *http_requestpool_object_ce; -extern zend_function_entry http_requestpool_object_fe[]; - -extern PHP_MINIT_FUNCTION(http_requestpool_object); - -#define http_requestpool_object_new(ce) _http_requestpool_object_new(ce TSRMLS_CC) -extern zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC); -#define http_requestpool_object_free(o) _http_requestpool_object_free(o TSRMLS_CC) -extern void _http_requestpool_object_free(zend_object *object TSRMLS_DC); - -PHP_METHOD(HttpRequestPool, __construct); -PHP_METHOD(HttpRequestPool, __destruct); -PHP_METHOD(HttpRequestPool, attach); -PHP_METHOD(HttpRequestPool, detach); -PHP_METHOD(HttpRequestPool, send); -PHP_METHOD(HttpRequestPool, reset); -PHP_METHOD(HttpRequestPool, socketPerform); -PHP_METHOD(HttpRequestPool, socketSelect); -PHP_METHOD(HttpRequestPool, valid); -PHP_METHOD(HttpRequestPool, current); -PHP_METHOD(HttpRequestPool, key); -PHP_METHOD(HttpRequestPool, next); -PHP_METHOD(HttpRequestPool, rewind); -PHP_METHOD(HttpRequestPool, count); -PHP_METHOD(HttpRequestPool, getAttachedRequests); -PHP_METHOD(HttpRequestPool, getFinishedRequests); -PHP_METHOD(HttpRequestPool, enablePipelining); -PHP_METHOD(HttpRequestPool, enableEvents); - -#endif -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_response_object.h b/php_http_response_object.h deleted file mode 100644 index 36a98b4..0000000 --- a/php_http_response_object.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_RESPONSE_OBJECT_H -#define PHP_HTTP_RESPONSE_OBJECT_H -#ifdef ZEND_ENGINE_2 -#ifndef WONKY - -extern zend_class_entry *http_response_object_ce; -extern zend_function_entry http_response_object_fe[]; - -extern PHP_MINIT_FUNCTION(http_response_object); - -PHP_METHOD(HttpResponse, setHeader); -PHP_METHOD(HttpResponse, getHeader); -PHP_METHOD(HttpResponse, setETag); -PHP_METHOD(HttpResponse, getETag); -PHP_METHOD(HttpResponse, setLastModified); -PHP_METHOD(HttpResponse, getLastModified); -PHP_METHOD(HttpResponse, setContentDisposition); -PHP_METHOD(HttpResponse, getContentDisposition); -PHP_METHOD(HttpResponse, setContentType); -PHP_METHOD(HttpResponse, getContentType); -PHP_METHOD(HttpResponse, guessContentType); -PHP_METHOD(HttpResponse, setCache); -PHP_METHOD(HttpResponse, getCache); -PHP_METHOD(HttpResponse, setCacheControl); -PHP_METHOD(HttpResponse, getCacheControl); -PHP_METHOD(HttpResponse, setGzip); -PHP_METHOD(HttpResponse, getGzip); -PHP_METHOD(HttpResponse, setThrottleDelay); -PHP_METHOD(HttpResponse, getThrottleDelay); -PHP_METHOD(HttpResponse, setBufferSize); -PHP_METHOD(HttpResponse, getBufferSize); -PHP_METHOD(HttpResponse, setData); -PHP_METHOD(HttpResponse, getData); -PHP_METHOD(HttpResponse, setFile); -PHP_METHOD(HttpResponse, getFile); -PHP_METHOD(HttpResponse, setStream); -PHP_METHOD(HttpResponse, getStream); -PHP_METHOD(HttpResponse, send); -PHP_METHOD(HttpResponse, capture); - -#endif -#endif -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_send_api.h b/php_http_send_api.h deleted file mode 100644 index 3449007..0000000 --- a/php_http_send_api.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_SEND_API_H -#define PHP_HTTP_SEND_API_H - -typedef enum _http_send_mode_t { - SEND_DATA, - SEND_RSRC -} http_send_mode; - -#define HTTP_REDIRECT 0L -#define HTTP_REDIRECT_PERM 301L -#define HTTP_REDIRECT_FOUND 302L -#define HTTP_REDIRECT_POST 303L -#define HTTP_REDIRECT_PROXY 305L -#define HTTP_REDIRECT_TEMP 307L - -extern PHP_MINIT_FUNCTION(http_send); - -#define http_send_status(s) sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (long) (s) TSRMLS_CC) -#define http_send_header(n, v, r) _http_send_header_ex((n), strlen(n), (v), strlen(v), (r), NULL TSRMLS_CC) -#define http_send_header_ex(n, nl, v, vl, r, s) _http_send_header_ex((n), (nl), (v), (vl), (r), (s) TSRMLS_CC) -PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace, char **sent_header TSRMLS_DC); -#define http_send_header_string(h) _http_send_status_header_ex(0, (h), strlen(h), 1 TSRMLS_CC) -#define http_send_header_string_ex(h, l, r) _http_send_status_header_ex(0, (h), (l), (r) TSRMLS_CC) -#define http_send_status_header(s, h) _http_send_status_header_ex((s), (h), (h)?strlen(h):0, 1 TSRMLS_CC) -#define http_send_status_header_ex(s, h, l, r) _http_send_status_header_ex((s), (h), (l), (r) TSRMLS_CC) -PHP_HTTP_API STATUS _http_send_status_header_ex(int status, const char *header, size_t header_len, zend_bool replace TSRMLS_DC); - -#define http_send_header_zval(n, z, r) http_send_header_zval_ex((n), strlen(n), (z), (r)) -#define http_send_header_zval_ex(n, l, z, r) _http_send_header_zval_ex((n), (l), (z), (r) TSRMLS_CC) -PHP_HTTP_API void _http_send_header_zval_ex(const char *name, size_t name_len, zval **val, zend_bool replace TSRMLS_DC); - -#define http_hide_header(h) http_hide_header_ex((h), strlen(h)) -#define http_hide_header_ex(h, l) _http_hide_header_ex((h), (l) TSRMLS_CC) -PHP_HTTP_API void _http_hide_header_ex(const char *name, size_t name_len TSRMLS_DC); - -#define http_send_last_modified(t) _http_send_last_modified_ex((t), NULL TSRMLS_CC) -#define http_send_last_modified_ex(t, s) _http_send_last_modified_ex((t), (s) TSRMLS_CC) -PHP_HTTP_API STATUS _http_send_last_modified_ex(time_t t, char **sent_header TSRMLS_DC); - -#define http_send_etag(e, l) _http_send_etag_ex((e), (l), NULL TSRMLS_CC) -#define http_send_etag_ex(e, l, s) _http_send_etag_ex((e), (l), (s) TSRMLS_CC) -PHP_HTTP_API STATUS _http_send_etag_ex(const char *etag, size_t etag_len, char **sent_header TSRMLS_DC); - -#define http_send_cache_control(cc, cl) http_send_header_ex("Cache-Control", lenof("Cache-Control"), (cc), (cl), 1, NULL) - -#define http_send_content_type(c, l) _http_send_content_type((c), (l) TSRMLS_CC) -PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_len TSRMLS_DC); - -#define http_send_content_disposition(f, l, i) _http_send_content_disposition((f), (l), (i) TSRMLS_CC) -PHP_HTTP_API STATUS _http_send_content_disposition(const char *filename, size_t f_len, zend_bool send_inline TSRMLS_DC); - -#define http_send_data(d, l) http_send((d), (l), SEND_DATA) -#define http_send_data_ex(d, l, nc) http_send_ex((d), (l), SEND_DATA, (nc)) -#define http_send(d, s, m) _http_send_ex((d), (s), (m), 0 TSRMLS_CC) -#define http_send_ex(d, s, m, nc) _http_send_ex((d), (s), (m), (nc) TSRMLS_CC) -PHP_HTTP_API STATUS _http_send_ex(const void *data, size_t data_size, http_send_mode mode, zend_bool no_cache TSRMLS_DC); - -#define http_send_file(f) http_send_stream_ex(php_stream_open_wrapper_ex(f, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT), 1, 0) -#define http_send_file_ex(f, nc) http_send_stream_ex(php_stream_open_wrapper_ex(f, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT), 1, (nc)) -#define http_send_stream(s) http_send_stream_ex((s), 0, 0) -#define http_send_stream_ex(s, c, nc) _http_send_stream_ex((s), (c), (nc) TSRMLS_CC) -PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *s, zend_bool close_stream, zend_bool no_cache TSRMLS_DC); - -#define http_guess_content_type(mf, mm, d, l, m) _http_guess_content_type((mf), (mm), (d), (l), (m) TSRMLS_CC) -PHP_HTTP_API char *_http_guess_content_type(const char *magic_file, long magic_mode, void *data_ptr, size_t data_len, http_send_mode mode TSRMLS_DC); - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_std_defs.h b/php_http_std_defs.h deleted file mode 100644 index 32c1233..0000000 --- a/php_http_std_defs.h +++ /dev/null @@ -1,410 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_STD_DEFS_H -#define PHP_HTTP_STD_DEFS_H - -#if defined(PHP_WIN32) -# if defined(HTTP_EXPORTS) -# define PHP_HTTP_API __declspec(dllexport) -# elif defined(COMPILE_DL_HTTP) -# define PHP_HTTP_API __declspec(dllimport) -# else -# define PHP_HTTP_API -# endif -#else -# define PHP_HTTP_API -#endif - -/* make functions that return SUCCESS|FAILURE more obvious */ -typedef int STATUS; - -/* lenof() */ -#define lenof(S) (sizeof(S) - 1) - -#ifndef MIN -# define MIN(a,b) (ab?a:b) -#endif - -/* STR_SET() */ -#ifndef STR_SET -# define STR_SET(STR, SET) \ - { \ - STR_FREE(STR); \ - STR = SET; \ - } -#endif - -#define STR_PTR(s) (s?s:"") - -#define INIT_ZARR(zv, ht) \ - { \ - INIT_PZVAL(&(zv)); \ - Z_TYPE(zv) = IS_ARRAY; \ - Z_ARRVAL(zv) = (ht); \ - } - -/* return bool (v == SUCCESS) */ -#define RETVAL_SUCCESS(v) RETVAL_BOOL(SUCCESS == (v)) -#define RETURN_SUCCESS(v) RETURN_BOOL(SUCCESS == (v)) -/* return object(values) */ -#define RETVAL_OBJECT(o, addref) \ - RETVAL_OBJVAL((o)->value.obj, addref) -#define RETURN_OBJECT(o, addref) \ - RETVAL_OBJECT(o, addref); \ - return -#define RETVAL_OBJVAL(ov, addref) \ - ZVAL_OBJVAL(return_value, ov, addref) -#define RETURN_OBJVAL(ov, addref) \ - RETVAL_OBJVAL(ov, addref); \ - return -#define ZVAL_OBJVAL(zv, ov, addref) \ - (zv)->type = IS_OBJECT; \ - (zv)->value.obj = (ov);\ - if (addref && Z_OBJ_HT_P(zv)->add_ref) { \ - Z_OBJ_HT_P(zv)->add_ref((zv) TSRMLS_CC); \ - } -/* return property */ -#define RETVAL_PROP(n) RETVAL_PROP_EX(getThis(), n) -#define RETURN_PROP(n) RETURN_PROP_EX(getThis(), n) -#define RETVAL_PROP_EX(this, n) \ - { \ - zval *__prop = zend_read_property(THIS_CE, this, ZEND_STRS(#n)-1, 0 TSRMLS_CC); \ - RETVAL_ZVAL(__prop, 1, 0); \ - } -#define RETURN_PROP_EX(this, n) \ - { \ - zval *__prop = zend_read_property(THIS_CE, this, ZEND_STRS(#n)-1, 0 TSRMLS_CC); \ - RETURN_ZVAL(__prop, 1, 0); \ - } - -/* function accepts no args */ -#define NO_ARGS zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, ""); - -/* CR LF */ -#define HTTP_CRLF "\r\n" - -/* default cache control */ -#define HTTP_DEFAULT_CACHECONTROL "private, must-revalidate, max-age=0" - -/* max URL length */ -#define HTTP_URL_MAXLEN 4096 - -/* max request method length */ -#define HTTP_REQUEST_METHOD_MAXLEN 31 - -/* def URL arg separator */ -#define HTTP_URL_ARGSEP "&" - -/* send buffer size */ -#define HTTP_SENDBUF_SIZE 40960 - -/* CURL buffer size */ -#define HTTP_CURLBUF_SIZE 16384 - -/* known methods */ -#define HTTP_KNOWN_METHODS \ - /* HTTP 1.1 */ \ - "GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE, CONNECT, " \ - /* WebDAV - RFC 2518 */ \ - "PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK, " \ - /* WebDAV Versioning - RFC 3253 */ \ - "VERSION-CONTROL, REPORT, CHECKOUT, CHECKIN, UNCHECKOUT, " \ - "MKWORKSPACE, UPDATE, LABEL, MERGE, BASELINE-CONTROL, MKACTIVITY, " \ - /* WebDAV Access Control - RFC 3744 */ \ - "ACL, " \ - /* END */ - -#ifdef ZEND_ENGINE_2 -# include "ext/standard/file.h" -# define HTTP_DEFAULT_STREAM_CONTEXT FG(default_context) -#else -# define HTTP_DEFAULT_STREAM_CONTEXT NULL -#endif - -#define HTTP_PHP_INI_ENTRY(entry, default, scope, updater, global) \ - STD_PHP_INI_ENTRY(entry, default, scope, updater, global, zend_http_globals, http_globals) -#define HTTP_PHP_INI_ENTRY_EX(entry, default, scope, updater, displayer, global) \ - STD_PHP_INI_ENTRY_EX(entry, default, scope, updater, global, zend_http_globals, http_globals, displayer) - - -#define HTTP_LONG_CONSTANT(name, const) REGISTER_LONG_CONSTANT(name, const, CONST_CS | CONST_PERSISTENT) - -/* {{{ objects & properties */ -#ifdef ZEND_ENGINE_2 - -# define HTTP_STATIC_ME_ALIAS(me, al, ai) ZEND_FENTRY(me, ZEND_FN(al), ai, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - -# define HTTP_REGISTER_CLASS_EX(classname, name, parent, flags) \ - { \ - zend_class_entry ce; \ - memset(&ce, 0, sizeof(zend_class_entry)); \ - INIT_CLASS_ENTRY(ce, #classname, name## _fe); \ - ce.create_object = _ ##name## _new; \ - name## _ce = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \ - name## _ce->ce_flags |= flags; \ - memcpy(& name## _handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \ - } - -# define HTTP_REGISTER_CLASS(classname, name, parent, flags) \ - { \ - zend_class_entry ce; \ - memset(&ce, 0, sizeof(zend_class_entry)); \ - INIT_CLASS_ENTRY(ce, #classname, name## _fe); \ - ce.create_object = NULL; \ - name## _ce = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \ - name## _ce->ce_flags |= flags; \ - } - -# define HTTP_REGISTER_EXCEPTION(classname, cename, parent) \ - { \ - zend_class_entry ce; \ - memset(&ce, 0, sizeof(zend_class_entry)); \ - INIT_CLASS_ENTRY(ce, #classname, NULL); \ - ce.create_object = NULL; \ - cename = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \ - } - -# define getObject(t, o) getObjectEx(t, o, getThis()) -# define getObjectEx(t, o, v) t * o = ((t *) zend_object_store_get_object(v TSRMLS_CC)) -# define putObject(t, o) zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) _ ##t## _free, NULL TSRMLS_CC); -# if defined(ZEND_ENGINE_2_4) -# define freeObject(o) \ - zend_object_std_dtor(o TSRMLS_CC); \ - efree(o); -# elif !defined(WONKY) -# define freeObject(o) \ - if (OBJ_GUARDS(o)) { \ - zend_hash_destroy(OBJ_GUARDS(o)); \ - FREE_HASHTABLE(OBJ_GUARDS(o)); \ - } \ - if (OBJ_PROP(o)) { \ - zend_hash_destroy(OBJ_PROP(o)); \ - FREE_HASHTABLE(OBJ_PROP(o)); \ - } \ - efree(o); -# else -# define freeObject(o) \ - if (OBJ_PROP(o)) { \ - zend_hash_destroy(OBJ_PROP(o)); \ - FREE_HASHTABLE(OBJ_PROP(o)); \ - } \ - efree(o); -# endif -# define OBJ_PROP(o) (o)->zo.properties -# define OBJ_GUARDS(o) (o)->zo.guards - -# define ACC_PROP_PRIVATE(ce, flags) ((flags & ZEND_ACC_PRIVATE) && (EG(scope) && ce == EG(scope)) -# define ACC_PROP_PROTECTED(ce, flags) ((flags & ZEND_ACC_PROTECTED) && (zend_check_protected(ce, EG(scope)))) -# define ACC_PROP_PUBLIC(flags) (flags & ZEND_ACC_PUBLIC) -# define ACC_PROP(ce, flags) (ACC_PROP_PUBLIC(flags) || ACC_PROP_PRIVATE(ce, flags) || ACC_PROP_PROTECTED(ce, flags)) - -# define SET_EH_THROW_HTTP() SET_EH_THROW_EX(http_exception_get_default()) -# define SET_EH_THROW_EX(ex) php_set_error_handling(EH_THROW, ex TSRMLS_CC) -# define SET_EH_NORMAL() php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC) - -#endif /* ZEND_ENGINE_2 */ -/* }}} */ - -#ifdef ZEND_ENGINE_2 -# define with_error_handling(eh, ec) \ - { \ - error_handling_t __eh = GLOBAL_ERROR_HANDLING; \ - zend_class_entry *__ec= GLOBAL_EXCEPTION_CLASS; \ - php_set_error_handling(eh, ec TSRMLS_CC); -# define end_error_handling() \ - php_set_error_handling(__eh, __ec TSRMLS_CC); \ - } -#else -# define with_error_handling(eh, ec) -# define end_error_handling() -#endif - -#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 2) || PHP_MAJOR_VERSION > 5 -# define ZEND_EXCEPTION_GET_DEFAULT() zend_exception_get_default(TSRMLS_C) -#else -# define ZEND_EXCEPTION_GET_DEFAULT() zend_exception_get_default() -#endif - -#ifndef E_THROW -# define E_THROW 0 -#endif -#ifdef ZEND_ENGINE_2 -# define HE_THROW E_THROW TSRMLS_CC -# define HE_NOTICE (HTTP_G->only_exceptions ? E_THROW : E_NOTICE) TSRMLS_CC -# define HE_WARNING (HTTP_G->only_exceptions ? E_THROW : E_WARNING) TSRMLS_CC -# define HE_ERROR (HTTP_G->only_exceptions ? E_THROW : E_ERROR) TSRMLS_CC -#else -# define HE_THROW E_WARNING TSRMLS_CC -# define HE_NOTICE E_NOTICE TSRMLS_CC -# define HE_WARNING E_WARNING TSRMLS_CC -# define HE_ERROR E_ERROR TSRMLS_CC -#endif - -#define HTTP_E_RUNTIME 1L -#define HTTP_E_INVALID_PARAM 2L -#define HTTP_E_HEADER 3L -#define HTTP_E_MALFORMED_HEADERS 4L -#define HTTP_E_REQUEST_METHOD 5L -#define HTTP_E_MESSAGE_TYPE 6L -#define HTTP_E_ENCODING 7L -#define HTTP_E_REQUEST 8L -#define HTTP_E_REQUEST_POOL 9L -#define HTTP_E_SOCKET 10L -#define HTTP_E_RESPONSE 11L -#define HTTP_E_URL 12L -#define HTTP_E_QUERYSTRING 13L - -#ifdef ZEND_ENGINE_2 -# define HTTP_BEGIN_ARGS_EX(class, method, ret_ref, req_args) HTTP_STATIC_ARG_INFO ZEND_BEGIN_ARG_INFO_EX(args_for_ ##class## _ ##method , 0, ret_ref, req_args) -# define HTTP_BEGIN_ARGS_AR(class, method, ret_ref, req_args) HTTP_STATIC_ARG_INFO ZEND_BEGIN_ARG_INFO_EX(args_for_ ##class## _ ##method , 1, ret_ref, req_args) -# define HTTP_END_ARGS } -# define HTTP_EMPTY_ARGS_EX(class, method, ret_ref) HTTP_BEGIN_ARGS_EX(class, method, ret_ref, 0) HTTP_END_ARGS -# define HTTP_ARGS(class, method) args_for_ ##class## _ ##method -# define HTTP_ARG_VAL(name, pass_ref) ZEND_ARG_INFO(pass_ref, name) -# define HTTP_ARG_OBJ(class, name, allow_null) ZEND_ARG_OBJ_INFO(0, name, class, allow_null) -#endif - -#ifdef ZEND_ENGINE_2 -# define EMPTY_FUNCTION_ENTRY {NULL, NULL, NULL, 0, 0} -#else -# define EMPTY_FUNCTION_ENTRY {NULL, NULL, NULL} -#endif - -#ifdef HTTP_HAVE_CURL -# ifdef ZEND_ENGINE_2 -# define HTTP_DECLARE_ARG_PASS_INFO() \ - HTTP_STATIC_ARG_INFO \ - ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_2, 0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(1) \ - ZEND_END_ARG_INFO(); \ - \ - HTTP_STATIC_ARG_INFO \ - ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_3, 0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(1) \ - ZEND_END_ARG_INFO(); \ - \ - HTTP_STATIC_ARG_INFO \ - ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_4, 0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(1) \ - ZEND_END_ARG_INFO(); \ - \ - HTTP_STATIC_ARG_INFO \ - ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_5, 0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(1) \ - ZEND_END_ARG_INFO(); - -# else -# define HTTP_DECLARE_ARG_PASS_INFO() \ - static unsigned char http_arg_pass_ref_2[] = {2, BYREF_NONE, BYREF_FORCE}; \ - static unsigned char http_arg_pass_ref_3[] = {3, BYREF_NONE, BYREF_NONE, BYREF_FORCE}; \ - static unsigned char http_arg_pass_ref_4[] = {4, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE}; \ - static unsigned char http_arg_pass_ref_5[] = {5, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE}; -# endif /* ZEND_ENGINE_2 */ -#else -# ifdef ZEND_ENGINE_2 -# define HTTP_DECLARE_ARG_PASS_INFO() \ - HTTP_STATIC_ARG_INFO \ - ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_2, 0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(1) \ - ZEND_END_ARG_INFO(); \ -\ - HTTP_STATIC_ARG_INFO \ - ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_3, 0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(1) \ - ZEND_END_ARG_INFO(); \ -\ - HTTP_STATIC_ARG_INFO \ - ZEND_BEGIN_ARG_INFO(http_arg_pass_ref_4, 0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(0) \ - ZEND_ARG_PASS_INFO(1) \ - ZEND_END_ARG_INFO(); -# else -# define HTTP_DECLARE_ARG_PASS_INFO() \ - static unsigned char http_arg_pass_ref_2[] = {2, BYREF_NONE, BYREF_FORCE}; \ - static unsigned char http_arg_pass_ref_3[] = {3, BYREF_NONE, BYREF_NONE, BYREF_FORCE}; \ - static unsigned char http_arg_pass_ref_4[] = {4, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE}; -# endif /* ZEND_ENGINE_2 */ -#endif /* HTTP_HAVE_CURL */ - - -#ifndef HAVE_CURL_SHARE_STRERROR -# define curl_share_strerror(dummy) "unknown error" -#endif -#ifndef HAVE_CURL_EASY_STRERROR -# define curl_easy_strerror(dummy) "unknown error" -#endif -#ifndef HAVE_CURL_MULTI_STRERROR -# define curl_multi_strerror(dummy) "unknown error" -#endif - -#define PHP_MINIT_CALL(func) PHP_MINIT(func)(INIT_FUNC_ARGS_PASSTHRU) -#define PHP_RINIT_CALL(func) PHP_RINIT(func)(INIT_FUNC_ARGS_PASSTHRU) -#define PHP_MSHUTDOWN_CALL(func) PHP_MSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU) -#define PHP_RSHUTDOWN_CALL(func) PHP_RSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU) - -#define Z_OBJ_DELREF(z) \ - if (Z_OBJ_HT(z)->del_ref) { \ - Z_OBJ_HT(z)->del_ref(&(z) TSRMLS_CC); \ - } -#define Z_OBJ_ADDREF(z) \ - if (Z_OBJ_HT(z)->add_ref) { \ - Z_OBJ_HT(z)->add_ref(&(z) TSRMLS_CC); \ - } -#define Z_OBJ_DELREF_P(z) \ - if (Z_OBJ_HT_P(z)->del_ref) { \ - Z_OBJ_HT_P(z)->del_ref((z) TSRMLS_CC); \ - } -#define Z_OBJ_ADDREF_P(z) \ - if (Z_OBJ_HT_P(z)->add_ref) { \ - Z_OBJ_HT_P(z)->add_ref((z) TSRMLS_CC); \ - } -#define Z_OBJ_DELREF_PP(z) \ - if (Z_OBJ_HT_PP(z)->del_ref) { \ - Z_OBJ_HT_PP(z)->del_ref(*(z) TSRMLS_CC); \ - } -#define Z_OBJ_ADDREF_PP(z) \ - if (Z_OBJ_HT_PP(z)->add_ref) { \ - Z_OBJ_HT_PP(z)->add_ref(*(z) TSRMLS_CC); \ - } - -#endif /* PHP_HTTP_STD_DEFS_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_strlist.c b/php_http_strlist.c new file mode 100644 index 0000000..4e316db --- /dev/null +++ b/php_http_strlist.c @@ -0,0 +1,109 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +php_http_strlist_iterator_t *php_http_strlist_iterator_init(php_http_strlist_iterator_t *iter, const char list[], unsigned factor) +{ + if (!iter) { + iter = emalloc(sizeof(*iter)); + } + memset(iter, 0, sizeof(*iter)); + + iter->p = &list[0]; + iter->factor = factor; + + return iter; +} + +const char *php_http_strlist_iterator_this(php_http_strlist_iterator_t *iter, unsigned *id) +{ + if (id) { + *id = (iter->major + 1) * iter->factor + iter->minor; + } + + return iter->p; +} + +const char *php_http_strlist_iterator_next(php_http_strlist_iterator_t *iter) +{ + if (*iter->p) { + while (*iter->p) { + ++iter->p; + } + ++iter->p; + ++iter->minor; + + if (!*iter->p) { + ++iter->p; + ++iter->major; + iter->minor = 0; + } + } + + return iter->p; +} + +void php_http_strlist_iterator_dtor(php_http_strlist_iterator_t *iter) +{ + +} + +void php_http_strlist_iterator_free(php_http_strlist_iterator_t **iter) +{ + if (*iter) { + efree(*iter); + *iter = NULL; + } +} + +const char *php_http_strlist_find(const char list[], unsigned factor, unsigned item) +{ + unsigned M = 0, m = 0, major, minor; + const char *p = &list[0]; + + if (factor) { + major = (item / factor) - 1; + minor = item % factor; + } else { + major = 0; + minor = item; + } + while (*p && major != M++) { + while (*p) { + while (*p) { + ++p; + } + ++p; + } + ++p; + } + + while (*p && minor != m++) { + while (*p) { + ++p; + } + ++p; + } + + return p; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_strlist.h b/php_http_strlist.h new file mode 100644 index 0000000..319113f --- /dev/null +++ b/php_http_strlist.h @@ -0,0 +1,49 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_STRLIST_H +#define PHP_HTTP_STRLIST_H + +#ifdef NUL +# undef NUL +#endif +#define NUL "\0" + +#define PHP_HTTP_STRLIST(name) const char name[] +#define PHP_HTTP_STRLIST_ITEM(item) item NUL +#define PHP_HTTP_STRLIST_NEXT NUL +#define PHP_HTTP_STRLIST_STOP NUL NUL + +PHP_HTTP_API const char *php_http_strlist_find(const char list[], unsigned factor, unsigned item); + +typedef struct php_http_strlist_iterator { + const char *p; + unsigned factor, major, minor; +} php_http_strlist_iterator_t; + +PHP_HTTP_API php_http_strlist_iterator_t *php_http_strlist_iterator_init(php_http_strlist_iterator_t *iter, const char list[], unsigned factor); +PHP_HTTP_API const char *php_http_strlist_iterator_this(php_http_strlist_iterator_t *iter, unsigned *id); +PHP_HTTP_API const char *php_http_strlist_iterator_next(php_http_strlist_iterator_t *iter); +PHP_HTTP_API void php_http_strlist_iterator_dtor(php_http_strlist_iterator_t *iter); +PHP_HTTP_API void php_http_strlist_iterator_free(php_http_strlist_iterator_t **iter); + +#endif /* PHP_HTTP_STRLIST_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_url.c b/php_http_url.c new file mode 100644 index 0000000..eb1d2a3 --- /dev/null +++ b/php_http_url.c @@ -0,0 +1,606 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +static inline char *localhostname(void) +{ + char hostname[1024] = {0}; + +#ifdef PHP_WIN32 + if (SUCCESS == gethostname(hostname, lenof(hostname))) { + return estrdup(hostname); + } +#elif defined(HAVE_GETHOSTNAME) + if (SUCCESS == gethostname(hostname, lenof(hostname))) { +# if defined(HAVE_GETDOMAINNAME) + size_t hlen = strlen(hostname); + if (hlen <= lenof(hostname) - lenof("(none)")) { + hostname[hlen++] = '.'; + if (SUCCESS == getdomainname(&hostname[hlen], lenof(hostname) - hlen)) { + if (!strcmp(&hostname[hlen], "(none)")) { + hostname[hlen - 1] = '\0'; + } + return estrdup(hostname); + } + } +# endif + if (strcmp(hostname, "(none)")) { + return estrdup(hostname); + } + } +#endif + return estrndup("localhost", lenof("localhost")); +} + +static inline unsigned port(const char *scheme) +{ + unsigned port = 80; + +#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R) + int rc; + size_t len = 0xff; + char *buf = NULL; + struct servent *se_res = NULL, se_buf = {0}; + + do { + buf = erealloc(buf, len); + rc = getservbyname_r(scheme, "tcp", &se_buf, buf, len, &se_res); + len *= 2; + } while (rc == ERANGE && len <= 0xfff); + + if (!rc) { + port = ntohs(se_res->s_port); + } + + efree(buf); +#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT) + struct servent *se; + + if ((se = getservbyname(scheme, "tcp")) && se->s_port) { + port = ntohs(se->s_port); + } +#endif + + return port; +} +static inline char *scheme(unsigned port) +{ + char *scheme; +#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R) + int rc; + size_t len = 0xff; + char *buf = NULL; + struct servent *se_res = NULL, se_buf = {0}; +#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT) + struct servent *se; +#endif + + switch (port) { + case 443: + scheme = estrndup("https", lenof("https")); + break; + +#if defined(ZTS) && !defined(HAVE_GETSERVBYPORT_R) + default: +#elif !defined(ZTS) && !defined(HAVE_GETSERVBYPORT) + default: +#endif + case 80: + case 0: + scheme = estrndup("http", lenof("http")); + break; + +#if defined(ZTS) && defined(HAVE_GETSERVBYPORT_R) + default: + do { + buf = erealloc(buf, len); + rc = getservbyport_r(htons(port), "tcp", &se_buf, buf, len, &se_res); + len *= 2; + } while (rc == ERANGE && len <= 0xfff); + + if (!rc && se_res) { + scheme = estrdup(se_res->s_name); + } else { + scheme = estrndup("http", lenof("http")); + } + + efree(buf); + break; + +#elif !defined(ZTS) && defined(HAVE_GETSERVBYPORT) + default: + if ((se = getservbyport(htons(port), "tcp")) && se->s_name) { + scheme = estrdup(se->s_name); + } else { + scheme = estrndup("http", lenof("http")); + } + break; +#endif + } + return scheme; +} + +static php_url *php_http_url_from_env(php_url *url TSRMLS_DC) +{ + zval *https, *zhost, *zport; + long port; + + if (!url) { + url = ecalloc(1, sizeof(*url)); + } + + /* port */ + zport = php_http_env_get_server_var(ZEND_STRL("SERVER_PORT"), 1 TSRMLS_CC); + if (zport && IS_LONG == is_numeric_string(Z_STRVAL_P(zport), Z_STRLEN_P(zport), &port, NULL, 0)) { + url->port = port; + } + + /* scheme */ + https = php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1 TSRMLS_CC); + if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) { + url->scheme = estrndup("https", lenof("https")); + } else { + url->scheme = scheme(url->port); + } + + /* host */ + if ((((zhost = php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1 TSRMLS_CC)) || + (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1 TSRMLS_CC)) || + (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_ADDR"), 1 TSRMLS_CC)))) && Z_STRLEN_P(zhost)) { + size_t stop_at = strspn(Z_STRVAL_P(zhost), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-."); + + url->host = estrndup(Z_STRVAL_P(zhost), stop_at); + } else { + url->host = localhostname(); + } + + /* path */ + if (SG(request_info).request_uri && SG(request_info).request_uri[0]) { + const char *q = strchr(SG(request_info).request_uri, '?'); + + if (q) { + url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri); + } else { + url->path = estrdup(SG(request_info).request_uri); + } + } + + /* query */ + if (SG(request_info).query_string && SG(request_info).query_string[0]) { + url->query = estrdup(SG(request_info).query_string); + } + + return url; +} + +void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC) +{ + php_url *url, *tmp_url = NULL; + + /* set from env if requested */ + if (flags & PHP_HTTP_URL_FROM_ENV) { + php_url *env_url = php_http_url_from_env(NULL TSRMLS_CC); + + php_http_url(flags ^ PHP_HTTP_URL_FROM_ENV, env_url, old_url, &tmp_url, NULL, NULL TSRMLS_CC); + + php_url_free(env_url); + old_url = tmp_url; + } + + url = ecalloc(1, sizeof(*url)); + +#define __URLSET(u,n) \ + ((u)&&(u)->n) +#define __URLCPY(n) \ + url->n = __URLSET(new_url,n) ? estrdup(new_url->n) : (__URLSET(old_url,n) ? estrdup(old_url->n) : NULL) + + if (!(flags & PHP_HTTP_URL_STRIP_PORT)) { + url->port = __URLSET(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0); + } + if (!(flags & PHP_HTTP_URL_STRIP_USER)) { + __URLCPY(user); + } + if (!(flags & PHP_HTTP_URL_STRIP_PASS)) { + __URLCPY(pass); + } + + __URLCPY(scheme); + __URLCPY(host); + + if (!(flags & PHP_HTTP_URL_STRIP_PATH)) { + if ((flags & PHP_HTTP_URL_JOIN_PATH) && __URLSET(old_url, path) && __URLSET(new_url, path) && *new_url->path != '/') { + size_t old_path_len = strlen(old_url->path), new_path_len = strlen(new_url->path); + + url->path = ecalloc(1, old_path_len + new_path_len + 1 + 1); + + strcat(url->path, old_url->path); + if (url->path[old_path_len - 1] != '/') { + php_dirname(url->path, old_path_len); + strcat(url->path, "/"); + } + strcat(url->path, new_url->path); + } else { + __URLCPY(path); + } + } + if (!(flags & PHP_HTTP_URL_STRIP_QUERY)) { + if ((flags & PHP_HTTP_URL_JOIN_QUERY) && __URLSET(new_url, query) && __URLSET(old_url, query)) { + zval qarr, qstr; + + INIT_PZVAL(&qstr); + INIT_PZVAL(&qarr); + array_init(&qarr); + + ZVAL_STRING(&qstr, old_url->query, 0); + php_http_querystring_update(&qarr, &qstr, NULL TSRMLS_CC); + ZVAL_STRING(&qstr, new_url->query, 0); + php_http_querystring_update(&qarr, &qstr, NULL TSRMLS_CC); + + ZVAL_NULL(&qstr); + php_http_querystring_update(&qarr, NULL, &qstr TSRMLS_CC); + url->query = Z_STRVAL(qstr); + zval_dtor(&qarr); + } else { + __URLCPY(query); + } + } + if (!(flags & PHP_HTTP_URL_STRIP_FRAGMENT)) { + __URLCPY(fragment); + } + + /* done with copy & combine & strip */ + + if (flags & PHP_HTTP_URL_FROM_ENV) { + /* free old_url we tainted above */ + php_url_free(tmp_url); + } + + /* set some sane defaults */ + + if (!url->scheme) { + url->scheme = estrndup("http", lenof("http")); + } + + if (!url->host) { + url->host = estrndup("localhost", lenof("localhost")); + } + + if (!url->path) { + url->path = estrndup("/", 1); + } else if (url->path[0] != '/') { + size_t plen = strlen(url->path); + char *path = emalloc(plen + 1 + 1); + + path[0] = '/'; + memcpy(&path[1], url->path, plen + 1); + STR_SET(url->path, path); + } + /* replace directory references if path is not a single slash */ + if ((flags & PHP_HTTP_URL_SANITIZE_PATH) + && url->path[0] && (url->path[0] != '/' || url->path[1])) { + char *ptr, *end = url->path + strlen(url->path) + 1; + + for (ptr = strchr(url->path, '/'); ptr; ptr = strchr(ptr, '/')) { + switch (ptr[1]) { + case '/': + memmove(&ptr[1], &ptr[2], end - &ptr[2]); + break; + + case '.': + switch (ptr[2]) { + case '\0': + ptr[1] = '\0'; + break; + + case '/': + memmove(&ptr[1], &ptr[3], end - &ptr[3]); + break; + + case '.': + if (ptr[3] == '/') { + char *pos = &ptr[4]; + while (ptr != url->path) { + if (*--ptr == '/') { + break; + } + } + memmove(&ptr[1], pos, end - pos); + break; + } else if (!ptr[3]) { + /* .. at the end */ + ptr[1] = '\0'; + } + /* no break */ + + default: + /* something else */ + ++ptr; + break; + } + break; + + default: + ++ptr; + break; + } + } + } + /* unset default ports */ + if (url->port) { + if ( ((url->port == 80) && !strcmp(url->scheme, "http")) + || ((url->port ==443) && !strcmp(url->scheme, "https")) + || ( url->port == port(url->scheme)) + ) { + url->port = 0; + } + } + + if (url_str) { + php_http_url_to_string(url, url_str, url_len TSRMLS_CC); + } + + if (url_ptr) { + *url_ptr = url; + } else { + php_url_free(url); + } +} + +STATUS php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len TSRMLS_DC) +{ + const char *arg_sep_str; + size_t arg_sep_len; + php_http_buffer_t *qstr = php_http_buffer_new(); + + php_http_url_argsep(&arg_sep_str, &arg_sep_len TSRMLS_CC); + + if (SUCCESS != php_http_url_encode_hash_ex(hash, qstr, arg_sep_str, arg_sep_len, "=", 1, pre_encoded_str, pre_encoded_len TSRMLS_CC)) { + php_http_buffer_free(&qstr); + return FAILURE; + } + + php_http_buffer_data(qstr, encoded_str, encoded_len); + php_http_buffer_free(&qstr); + + return SUCCESS; +} + +STATUS php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len TSRMLS_DC) +{ + if (pre_encoded_len && pre_encoded_str) { + php_http_buffer_append(qstr, pre_encoded_str, pre_encoded_len); + } + + if (!php_http_params_to_string(qstr, hash, arg_sep_str, arg_sep_len, "", 0, val_sep_str, val_sep_len, PHP_HTTP_PARAMS_QUERY TSRMLS_CC)) { + return FAILURE; + } + + return SUCCESS; +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl___construct, 0, 0, 0) + ZEND_ARG_INFO(0, old_url) + ZEND_ARG_INFO(0, new_url) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpUrl, __construct) +{ + zval *new_url = NULL, *old_url = NULL; + long flags = PHP_HTTP_URL_FROM_ENV; + zend_error_handling zeh; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!z!l", &old_url, &new_url, &flags), invalid_arg, return); + + zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh TSRMLS_CC); + { + php_url *res_purl, *new_purl = NULL, *old_purl = NULL; + + if (new_url) { + switch (Z_TYPE_P(new_url)) { + case IS_OBJECT: + case IS_ARRAY: + new_purl = php_http_url_from_struct(NULL, HASH_OF(new_url) TSRMLS_CC); + break; + default: { + zval *cpy = php_http_ztyp(IS_STRING, new_url); + + new_purl = php_url_parse(Z_STRVAL_P(cpy)); + zval_ptr_dtor(&cpy); + break; + } + } + if (!new_purl) { + zend_restore_error_handling(&zeh TSRMLS_CC); + return; + } + } + if (old_url) { + switch (Z_TYPE_P(old_url)) { + case IS_OBJECT: + case IS_ARRAY: + old_purl = php_http_url_from_struct(NULL, HASH_OF(old_url) TSRMLS_CC); + break; + default: { + zval *cpy = php_http_ztyp(IS_STRING, old_url); + + old_purl = php_url_parse(Z_STRVAL_P(cpy)); + zval_ptr_dtor(&cpy); + break; + } + } + if (!old_purl) { + if (new_purl) { + php_url_free(new_purl); + } + zend_restore_error_handling(&zeh TSRMLS_CC); + return; + } + } + + php_http_url(flags, old_purl, new_purl, &res_purl, NULL, NULL TSRMLS_CC); + php_http_url_to_struct(res_purl, getThis() TSRMLS_CC); + + php_url_free(res_purl); + if (old_purl) { + php_url_free(old_purl); + } + if (new_purl) { + php_url_free(new_purl); + } + } + zend_restore_error_handling(&zeh TSRMLS_CC); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_mod, 0, 0, 1) + ZEND_ARG_INFO(0, more_url_parts) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpUrl, mod) +{ + zval *new_url = NULL; + long flags = PHP_HTTP_URL_JOIN_PATH | PHP_HTTP_URL_JOIN_QUERY; + zend_error_handling zeh; + + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!|l", &new_url, &flags), invalid_arg, return); + + zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh TSRMLS_CC); + { + php_url *new_purl = NULL, *old_purl = NULL; + + if (new_url) { + switch (Z_TYPE_P(new_url)) { + case IS_OBJECT: + case IS_ARRAY: + new_purl = php_http_url_from_struct(NULL, HASH_OF(new_url) TSRMLS_CC); + break; + default: { + zval *cpy = php_http_ztyp(IS_STRING, new_url); + + new_purl = php_url_parse(Z_STRVAL_P(new_url)); + zval_ptr_dtor(&cpy); + break; + } + } + if (!new_purl) { + zend_restore_error_handling(&zeh TSRMLS_CC); + return; + } + } + + if ((old_purl = php_http_url_from_struct(NULL, HASH_OF(getThis()) TSRMLS_CC))) { + php_url *res_purl; + + ZVAL_OBJVAL(return_value, zend_objects_clone_obj(getThis() TSRMLS_CC), 0); + + php_http_url(flags, old_purl, new_purl, &res_purl, NULL, NULL TSRMLS_CC); + php_http_url_to_struct(res_purl, return_value TSRMLS_CC); + + php_url_free(res_purl); + php_url_free(old_purl); + } + if (new_purl) { + php_url_free(new_purl); + } + } + zend_restore_error_handling(&zeh TSRMLS_CC); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_toString, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpUrl, toString) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_url *purl; + + if ((purl = php_http_url_from_struct(NULL, HASH_OF(getThis()) TSRMLS_CC))) { + char *str; + size_t len; + + php_http_url(0, purl, NULL, NULL, &str, &len TSRMLS_CC); + php_url_free(purl); + RETURN_STRINGL(str, len, 0); + } + } + RETURN_EMPTY_STRING(); +} + +ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_toArray, 0, 0, 0) +ZEND_END_ARG_INFO(); +PHP_METHOD(HttpUrl, toArray) +{ + php_url *purl; + + if (SUCCESS != zend_parse_parameters_none()) { + return; + } + + /* strip any non-URL properties */ + purl = php_http_url_from_struct(NULL, HASH_OF(getThis()) TSRMLS_CC); + php_http_url_to_struct(purl, return_value TSRMLS_CC); + php_url_free(purl); +} + +static zend_function_entry php_http_url_methods[] = { + PHP_ME(HttpUrl, __construct, ai_HttpUrl___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpUrl, mod, ai_HttpUrl_mod, ZEND_ACC_PUBLIC) + PHP_ME(HttpUrl, toString, ai_HttpUrl_toString, ZEND_ACC_PUBLIC) + ZEND_MALIAS(HttpUrl, __toString, toString, ai_HttpUrl_toString, ZEND_ACC_PUBLIC) + PHP_ME(HttpUrl, toArray, ai_HttpUrl_toArray, ZEND_ACC_PUBLIC) + EMPTY_FUNCTION_ENTRY +}; + +zend_class_entry *php_http_url_class_entry; + +PHP_MINIT_FUNCTION(http_url) +{ + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "Url", php_http_url_methods); + php_http_url_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + + zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("scheme"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("path"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("query"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("fragment"), ZEND_ACC_PUBLIC TSRMLS_CC); + + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("REPLACE"), PHP_HTTP_URL_REPLACE TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_PATH"), PHP_HTTP_URL_JOIN_PATH TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_QUERY"), PHP_HTTP_URL_JOIN_QUERY TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_USER"), PHP_HTTP_URL_STRIP_USER TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PASS"), PHP_HTTP_URL_STRIP_PASS TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_AUTH"), PHP_HTTP_URL_STRIP_AUTH TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PORT"), PHP_HTTP_URL_STRIP_PORT TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PATH"), PHP_HTTP_URL_STRIP_PATH TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_QUERY"), PHP_HTTP_URL_STRIP_QUERY TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_FRAGMENT"), PHP_HTTP_URL_STRIP_FRAGMENT TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_ALL"), PHP_HTTP_URL_STRIP_ALL TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("FROM_ENV"), PHP_HTTP_URL_FROM_ENV TSRMLS_CC); + zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("SANITIZE_PATH"), PHP_HTTP_URL_SANITIZE_PATH TSRMLS_CC); + + return SUCCESS; +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_url.h b/php_http_url.h new file mode 100644 index 0000000..938cf07 --- /dev/null +++ b/php_http_url.h @@ -0,0 +1,230 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_URL_H +#define PHP_HTTP_URL_H + +#include + +#define PHP_HTTP_URL_REPLACE 0x000 +#define PHP_HTTP_URL_JOIN_PATH 0x001 +#define PHP_HTTP_URL_JOIN_QUERY 0x002 +#define PHP_HTTP_URL_STRIP_USER 0x004 +#define PHP_HTTP_URL_STRIP_PASS 0x008 +#define PHP_HTTP_URL_STRIP_AUTH (PHP_HTTP_URL_STRIP_USER|PHP_HTTP_URL_STRIP_PASS) +#define PHP_HTTP_URL_STRIP_PORT 0x020 +#define PHP_HTTP_URL_STRIP_PATH 0x040 +#define PHP_HTTP_URL_STRIP_QUERY 0x080 +#define PHP_HTTP_URL_STRIP_FRAGMENT 0x100 +#define PHP_HTTP_URL_STRIP_ALL ( \ + PHP_HTTP_URL_STRIP_AUTH | \ + PHP_HTTP_URL_STRIP_PORT | \ + PHP_HTTP_URL_STRIP_PATH | \ + PHP_HTTP_URL_STRIP_QUERY | \ + PHP_HTTP_URL_STRIP_FRAGMENT \ +) +#define PHP_HTTP_URL_FROM_ENV 0x1000 +#define PHP_HTTP_URL_SANITIZE_PATH 0x2000 + +PHP_HTTP_API void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC); + +PHP_HTTP_API STATUS php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len TSRMLS_DC); +PHP_HTTP_API STATUS php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len TSRMLS_DC); + +static inline void php_http_url_argsep(const char **str, size_t *len TSRMLS_DC) +{ + if (SUCCESS != php_http_ini_entry(ZEND_STRL("arg_separator.output"), str, len, 0 TSRMLS_CC) || !*len) { + *str = PHP_HTTP_URL_ARGSEP; + *len = lenof(PHP_HTTP_URL_ARGSEP); + } +} + +static inline void php_http_url_to_string(php_url *url, char **url_str, size_t *url_len TSRMLS_DC) +{ + php_http_buffer_t buf; + + php_http_buffer_init(&buf); + + if (url->scheme && *url->scheme) { + php_http_buffer_appendl(&buf, url->scheme); + php_http_buffer_appends(&buf, "://"); + } else { + php_http_buffer_appends(&buf, "//"); + } + + if (url->user && *url->user) { + php_http_buffer_appendl(&buf, url->user); + if (url->pass && *url->pass) { + php_http_buffer_appends(&buf, ":"); + php_http_buffer_appendl(&buf, url->pass); + } + php_http_buffer_appends(&buf, "@"); + } + + if (url->host && *url->host) { + php_http_buffer_appendl(&buf, url->host); + } else { + php_http_buffer_appends(&buf, "localhost"); + } + + if (url->port) { + php_http_buffer_appendf(&buf, ":%hu", url->port); + } + + if (url->path && *url->path) { + php_http_buffer_appendl(&buf, url->path); + } + + if (url->query && *url->query) { + php_http_buffer_appends(&buf, "?"); + php_http_buffer_appendl(&buf, url->query); + } + + if (url->fragment && *url->fragment) { + php_http_buffer_appends(&buf, "#"); + php_http_buffer_appendl(&buf, url->fragment); + } + + php_http_buffer_shrink(&buf); + php_http_buffer_fix(&buf); + + if (url_len) { + *url_len = buf.used; + } + + if (url_str) { + *url_str = buf.data; + } else { + php_http_buffer_dtor(&buf); + } +} + +static inline php_url *php_http_url_from_struct(php_url *url, HashTable *ht TSRMLS_DC) +{ + zval **e; + + if (!url) { + url = emalloc(sizeof(*url)); + } + memset(url, 0, sizeof(*url)); + + if (SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void *) &e)) { + zval *cpy = php_http_ztyp(IS_STRING, *e); + url->scheme = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); + zval_ptr_dtor(&cpy); + } + if (SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void *) &e)) { + zval *cpy = php_http_ztyp(IS_STRING, *e); + url->user = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); + zval_ptr_dtor(&cpy); + } + if (SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void *) &e)) { + zval *cpy = php_http_ztyp(IS_STRING, *e); + url->pass = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); + zval_ptr_dtor(&cpy); + } + if (SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void *) &e)) { + zval *cpy = php_http_ztyp(IS_STRING, *e); + url->host = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); + zval_ptr_dtor(&cpy); + } + if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &e)) { + zval *cpy = php_http_ztyp(IS_STRING, *e); + url->path = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); + zval_ptr_dtor(&cpy); + } + if (SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void *) &e)) { + zval *cpy = php_http_ztyp(IS_STRING, *e); + url->query = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); + zval_ptr_dtor(&cpy); + } + if (SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void *) &e)) { + zval *cpy = php_http_ztyp(IS_STRING, *e); + url->fragment = estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)); + zval_ptr_dtor(&cpy); + } + if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void *) &e)) { + zval *cpy = php_http_ztyp(IS_LONG, *e); + url->port = (unsigned short) Z_LVAL_P(cpy); + zval_ptr_dtor(&cpy); + } + + return url; +} + +static inline HashTable *php_http_url_to_struct(php_url *url, zval *strct TSRMLS_DC) +{ + zval arr; + + if (strct) { + switch (Z_TYPE_P(strct)) { + default: + zval_dtor(strct); + array_init(strct); + /* no break */ + case IS_ARRAY: + case IS_OBJECT: + INIT_PZVAL_ARRAY((&arr), HASH_OF(strct)); + break; + } + } else { + INIT_PZVAL(&arr); + array_init(&arr); + } + + if (url) { + if (url->scheme) { + add_assoc_string(&arr, "scheme", url->scheme, 1); + } + if (url->user) { + add_assoc_string(&arr, "user", url->user, 1); + } + if (url->pass) { + add_assoc_string(&arr, "pass", url->pass, 1); + } + if (url->host) { + add_assoc_string(&arr, "host", url->host, 1); + } + if (url->port) { + add_assoc_long(&arr, "port", (long) url->port); + } + if (url->path) { + add_assoc_string(&arr, "path", url->path, 1); + } + if (url->query) { + add_assoc_string(&arr, "query", url->query, 1); + } + if (url->fragment) { + add_assoc_string(&arr, "fragment", url->fragment, 1); + } + } + + return Z_ARRVAL(arr); +} + +PHP_HTTP_API zend_class_entry *php_http_url_class_entry; +PHP_MINIT_FUNCTION(http_url); + +#define php_http_url_object_new php_http_object_new +#define php_http_url_object_new_ex php_http_object_new_ex + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_url_api.h b/php_http_url_api.h deleted file mode 100644 index 940db8e..0000000 --- a/php_http_url_api.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2010, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_HTTP_URL_API_H -#define PHP_HTTP_URL_API_H - -#include "ext/standard/url.h" - -extern PHP_MINIT_FUNCTION(http_url); - -#define http_absolute_url(u) _http_absolute_url_ex((u), HTTP_URL_REPLACE TSRMLS_CC) -#define http_absolute_url_ex(u, f) _http_absolute_url_ex((u), (f) TSRMLS_CC) -PHP_HTTP_API char *_http_absolute_url_ex(const char *url, int flags TSRMLS_DC); - -#define HTTP_URL_REPLACE 0x000 -#define HTTP_URL_JOIN_PATH 0x001 -#define HTTP_URL_JOIN_QUERY 0x002 -#define HTTP_URL_STRIP_USER 0x004 -#define HTTP_URL_STRIP_PASS 0x008 -#define HTTP_URL_STRIP_AUTH (HTTP_URL_STRIP_USER|HTTP_URL_STRIP_PASS) -#define HTTP_URL_STRIP_PORT 0x020 -#define HTTP_URL_STRIP_PATH 0x040 -#define HTTP_URL_STRIP_QUERY 0x080 -#define HTTP_URL_STRIP_FRAGMENT 0x100 -#define HTTP_URL_STRIP_ALL ( \ - HTTP_URL_STRIP_AUTH | \ - HTTP_URL_STRIP_PORT | \ - HTTP_URL_STRIP_PATH | \ - HTTP_URL_STRIP_QUERY | \ - HTTP_URL_STRIP_FRAGMENT \ -) -#define HTTP_URL_FROM_ENV 0x1000 - -#define http_build_url(f, o, n, p, s, l) _http_build_url((f), (o), (n), (p), (s), (l) TSRMLS_CC) -PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC); - -#define http_urlencode_hash(h, q) _http_urlencode_hash_ex((h), 1, NULL, 0, (q), NULL TSRMLS_CC) -#define http_urlencode_hash_ex(h, o, p, pl, q, ql) _http_urlencode_hash_ex((h), (o), (p), (pl), (q), (ql) TSRMLS_CC) -PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep, char *pre_encoded_data, size_t pre_encoded_len, char **encoded_data, size_t *encoded_len TSRMLS_DC); - -#define http_urlencode_hash_recursive(ht, s, as, al, pr, pl) _http_urlencode_hash_recursive((ht), (s), (as), (al), (pr), (pl) TSRMLS_CC) -PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC); - -#define http_url_from_struct(u, ht) _http_url_from_struct((u), (ht) TSRMLS_CC) -static inline php_url *_http_url_from_struct(php_url *url, HashTable *ht TSRMLS_DC) -{ - zval **e; - - if (!url) { - url = ecalloc(1, sizeof(php_url)); - } - - if ((SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void *) &e)) - && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { - url->scheme = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); - } - if ((SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void *) &e)) - && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { - url->user = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); - } - if ((SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void *) &e)) - && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { - url->pass = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); - } - if ((SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void *) &e)) - && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { - url->host = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); - } - if ((SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &e)) - && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { - url->path = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); - } - if ((SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void *) &e)) - && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { - url->query = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); - } - if ((SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void *) &e)) - && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { - url->fragment = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); - } - if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void *) &e)) { - if (Z_TYPE_PP(e) == IS_LONG) { - url->port = (unsigned short) Z_LVAL_PP(e); - } else { - zval *o = http_zsep(IS_LONG, *e); - - url->port = (unsigned short) Z_LVAL_P(o); - zval_ptr_dtor(&o); - } - } - - return url; -} - -#define http_url_tostruct(u, strct) _http_url_tostruct((u), (strct) TSRMLS_CC) -static inline HashTable *_http_url_tostruct(php_url *url, zval *strct TSRMLS_DC) -{ - zval arr; - - if (strct) { - switch (Z_TYPE_P(strct)) { - default: - zval_dtor(strct); - array_init(strct); - case IS_ARRAY: - case IS_OBJECT: - INIT_ZARR(arr, HASH_OF(strct)); - } - } else { - INIT_PZVAL(&arr); - array_init(&arr); - } - - if (url) { - if (url->scheme) { - add_assoc_string(&arr, "scheme", url->scheme, 1); - } - if (url->user) { - add_assoc_string(&arr, "user", url->user, 1); - } - if (url->pass) { - add_assoc_string(&arr, "pass", url->pass, 1); - } - if (url->host) { - add_assoc_string(&arr, "host", url->host, 1); - } - if (url->port) { - add_assoc_long(&arr, "port", (long) url->port); - } - if (url->path) { - add_assoc_string(&arr, "path", url->path, 1); - } - if (url->query) { - add_assoc_string(&arr, "query", url->query, 1); - } - if (url->fragment) { - add_assoc_string(&arr, "fragment", url->fragment, 1); - } - } - - return Z_ARRVAL(arr); -} - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_version.c b/php_http_version.c new file mode 100644 index 0000000..4b80504 --- /dev/null +++ b/php_http_version.c @@ -0,0 +1,72 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" + +php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major, unsigned minor TSRMLS_DC) +{ + if (!v) { + v = emalloc(sizeof(*v)); + } + + v->major = major; + v->minor = minor; + + return v; +} + +php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str TSRMLS_DC) +{ + php_http_version_t tmp; + char separator = 0; + + if (3 != sscanf(str, "HTTP/%u%c%u", &tmp.major, &separator, &tmp.minor) + && 3 != sscanf(str, "%u%c%u", &tmp.major, &separator, &tmp.minor)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP protocol version '%s'", str); + return NULL; + } + + if (separator && separator != '.' && separator != ',') { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, str); + } + + return php_http_version_init(v, tmp.major, tmp.minor TSRMLS_CC); +} + +void php_http_version_to_string(php_http_version_t *v, char **str, size_t *len, const char *pre, const char *post TSRMLS_DC) +{ + *len = spprintf(str, 0, "%s%u.%u%s", pre ? pre : "", v->major, v->minor, post ? post : ""); +} + +void php_http_version_dtor(php_http_version_t *v) +{ + (void) v; +} + +void php_http_version_free(php_http_version_t **v) +{ + if (*v) { + php_http_version_dtor(*v); + efree(*v); + *v = NULL; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/php_http_version.h b/php_http_version.h new file mode 100644 index 0000000..8053646 --- /dev/null +++ b/php_http_version.h @@ -0,0 +1,38 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2013, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_VERSION_H +#define PHP_HTTP_VERSION_H + +typedef struct php_http_version { + unsigned major; + unsigned minor; +} php_http_version_t; + +PHP_HTTP_API php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major, unsigned minor TSRMLS_DC); +PHP_HTTP_API php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str TSRMLS_DC); +PHP_HTTP_API void php_http_version_to_string(php_http_version_t *v, char **str, size_t *len, const char *pre, const char *post TSRMLS_DC); +PHP_HTTP_API void php_http_version_dtor(php_http_version_t *v); +PHP_HTTP_API void php_http_version_free(php_http_version_t **v); + +#endif /* PHP_HTTP_VERSION_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/phpstr/phpstr.c b/phpstr/phpstr.c deleted file mode 100644 index eb2f87a..0000000 --- a/phpstr/phpstr.c +++ /dev/null @@ -1,379 +0,0 @@ - -/* $Id$ */ - -#include "php.h" -#include "phpstr.h" - -PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, int flags) -{ - if (!buf) { - buf = pemalloc(sizeof(phpstr), flags & PHPSTR_INIT_PERSISTENT); - } - - if (buf) { - buf->size = (chunk_size) ? chunk_size : PHPSTR_DEFAULT_SIZE; - buf->pmem = (flags & PHPSTR_INIT_PERSISTENT) ? 1 : 0; - buf->data = (flags & PHPSTR_INIT_PREALLOC) ? pemalloc(buf->size, buf->pmem) : NULL; - buf->free = (flags & PHPSTR_INIT_PREALLOC) ? buf->size : 0; - buf->used = 0; - } - - return buf; -} - -PHPSTR_API phpstr *phpstr_from_string_ex(phpstr *buf, const char *string, size_t length) -{ - if ((buf = phpstr_init(buf))) { - if (PHPSTR_NOMEM == phpstr_append(buf, string, length)) { - pefree(buf, buf->pmem); - buf = NULL; - } - } - return buf; -} - -PHPSTR_API size_t phpstr_resize_ex(phpstr *buf, size_t len, size_t override_size, int allow_error) -{ - char *ptr = NULL; -#if 0 - fprintf(stderr, "RESIZE: size=%lu, used=%lu, free=%lu\n", buf->size, buf->used, buf->free); -#endif - if (buf->free < len) { - size_t size = override_size ? override_size : buf->size; - - while ((size + buf->free) < len) { - size <<= 1; - } - - if (allow_error) { - ptr = perealloc_recoverable(buf->data, buf->used + buf->free + size, buf->pmem); - } else { - ptr = perealloc(buf->data, buf->used + buf->free + size, buf->pmem); - } - - if (ptr) { - buf->data = ptr; - } else { - return PHPSTR_NOMEM; - } - - buf->free += size; - return size; - } - return 0; -} - -PHPSTR_API size_t phpstr_shrink(phpstr *buf) -{ - /* avoid another realloc on fixation */ - if (buf->free > 1) { - char *ptr = perealloc(buf->data, buf->used + 1, buf->pmem); - - if (ptr) { - buf->data = ptr; - } else { - return PHPSTR_NOMEM; - } - buf->free = 1; - } - return buf->used; -} - -PHPSTR_API size_t phpstr_append(phpstr *buf, const char *append, size_t append_len) -{ - if (PHPSTR_NOMEM == phpstr_resize(buf, append_len)) { - return PHPSTR_NOMEM; - } - memcpy(buf->data + buf->used, append, append_len); - buf->used += append_len; - buf->free -= append_len; - return append_len; -} - -PHPSTR_API size_t phpstr_appendf(phpstr *buf, const char *format, ...) -{ - va_list argv; - char *append; - size_t append_len, alloc; - - va_start(argv, format); - append_len = vspprintf(&append, 0, format, argv); - va_end(argv); - - alloc = phpstr_append(buf, append, append_len); - efree(append); - - if (PHPSTR_NOMEM == alloc) { - return PHPSTR_NOMEM; - } - return append_len; -} - -PHPSTR_API size_t phpstr_insert(phpstr *buf, const char *insert, size_t insert_len, size_t offset) -{ - if (PHPSTR_NOMEM == phpstr_resize(buf, insert_len)) { - return PHPSTR_NOMEM; - } - memmove(buf->data + offset + insert_len, buf->data + offset, insert_len); - memcpy(buf->data + offset, insert, insert_len); - buf->used += insert_len; - buf->free -= insert_len; - return insert_len; -} - -PHPSTR_API size_t phpstr_insertf(phpstr *buf, size_t offset, const char *format, ...) -{ - va_list argv; - char *insert; - size_t insert_len, alloc; - - va_start(argv, format); - insert_len = vspprintf(&insert, 0, format, argv); - va_end(argv); - - alloc = phpstr_insert(buf, insert, insert_len, offset); - efree(insert); - - if (PHPSTR_NOMEM == alloc) { - return PHPSTR_NOMEM; - } - return insert_len; -} - -PHPSTR_API size_t phpstr_prepend(phpstr *buf, const char *prepend, size_t prepend_len) -{ - if (PHPSTR_NOMEM == phpstr_resize(buf, prepend_len)) { - return PHPSTR_NOMEM; - } - memmove(buf->data + prepend_len, buf->data, buf->used); - memcpy(buf->data, prepend, prepend_len); - buf->used += prepend_len; - buf->free -= prepend_len; - return prepend_len; -} - -PHPSTR_API size_t phpstr_prependf(phpstr *buf, const char *format, ...) -{ - va_list argv; - char *prepend; - size_t prepend_len, alloc; - - va_start(argv, format); - prepend_len = vspprintf(&prepend, 0, format, argv); - va_end(argv); - - alloc = phpstr_prepend(buf, prepend, prepend_len); - efree(prepend); - - if (PHPSTR_NOMEM == alloc) { - return PHPSTR_NOMEM; - } - return prepend_len; -} - -PHPSTR_API char *phpstr_data(const phpstr *buf, char **into, size_t *len) -{ - char *copy = ecalloc(1, buf->used + 1); - memcpy(copy, buf->data, buf->used); - if (into) { - *into = copy; - } - if (len) { - *len = buf->used; - } - return copy; -} - -PHPSTR_API phpstr *phpstr_dup(const phpstr *buf) -{ - phpstr *dup = phpstr_clone(buf); - if (PHPSTR_NOMEM == phpstr_append(dup, buf->data, buf->used)) { - phpstr_free(&dup); - } - return dup; -} - -PHPSTR_API size_t phpstr_cut(phpstr *buf, size_t offset, size_t length) -{ - if (offset >= buf->used) { - return 0; - } - if (offset + length > buf->used) { - length = buf->used - offset; - } - memmove(buf->data + offset, buf->data + offset + length, buf->used - length); - buf->used -= length; - buf->free += length; - return length; -} - -PHPSTR_API phpstr *phpstr_sub(const phpstr *buf, size_t offset, size_t length) -{ - if (offset >= buf->used) { - return NULL; - } else { - size_t need = 1 + ((length + offset) > buf->used ? (buf->used - offset) : (length - offset)); - phpstr *sub = phpstr_init_ex(NULL, need, PHPSTR_INIT_PREALLOC | (buf->pmem ? PHPSTR_INIT_PERSISTENT:0)); - if (sub) { - if (PHPSTR_NOMEM == phpstr_append(sub, buf->data + offset, need)) { - phpstr_free(&sub); - } else { - sub->size = buf->size; - } - } - return sub; - } -} - -PHPSTR_API phpstr *phpstr_right(const phpstr *buf, size_t length) -{ - if (length < buf->used) { - return phpstr_sub(buf, buf->used - length, length); - } else { - return phpstr_sub(buf, 0, buf->used); - } -} - - -PHPSTR_API phpstr *phpstr_merge_va(phpstr *buf, unsigned argc, va_list argv) -{ - unsigned i = 0; - buf = phpstr_init(buf); - - if (buf) { - while (argc > i++) { - phpstr_free_t f = va_arg(argv, phpstr_free_t); - phpstr *current = va_arg(argv, phpstr *); - phpstr_append(buf, current->data, current->used); - FREE_PHPSTR(f, current); - } - } - - return buf; -} - -PHPSTR_API phpstr *phpstr_merge_ex(phpstr *buf, unsigned argc, ...) -{ - va_list argv; - phpstr *ret; - - va_start(argv, argc); - ret = phpstr_merge_va(buf, argc, argv); - va_end(argv); - return ret; -} - -PHPSTR_API phpstr *phpstr_merge(unsigned argc, ...) -{ - va_list argv; - phpstr *ret; - - va_start(argv, argc); - ret = phpstr_merge_va(NULL, argc, argv); - va_end(argv); - return ret; -} - -PHPSTR_API phpstr *phpstr_fix(phpstr *buf) -{ - if (PHPSTR_NOMEM == phpstr_resize_ex(buf, 1, 1, 0)) { - return NULL; - } - buf->data[buf->used] = '\0'; - return buf; -} - -PHPSTR_API int phpstr_cmp(phpstr *left, phpstr *right) -{ - if (left->used > right->used) { - return -1; - } else if (right->used > left->used) { - return 1; - } else { - return memcmp(left->data, right->data, left->used); - } -} - -PHPSTR_API void phpstr_reset(phpstr *buf) -{ - buf->free += buf->used; - buf->used = 0; -} - -PHPSTR_API void phpstr_dtor(phpstr *buf) -{ - if (buf->data) { - pefree(buf->data, buf->pmem); - buf->data = NULL; - } - buf->used = 0; - buf->free = 0; -} - -PHPSTR_API void phpstr_free(phpstr **buf) -{ - if (*buf) { - phpstr_dtor(*buf); - pefree(*buf, (*buf)->pmem); - *buf = NULL; - } -} - -PHPSTR_API size_t phpstr_chunk_buffer(phpstr **s, const char *data, size_t data_len, char **chunk, size_t chunk_size) -{ - phpstr *storage; - - *chunk = NULL; - - if (!*s) { - *s = phpstr_init_ex(NULL, chunk_size << 1, chunk_size ? PHPSTR_INIT_PREALLOC : 0); - } - storage = *s; - - if (data_len) { - phpstr_append(storage, data, data_len); - } - - if (!chunk_size) { - phpstr_data(storage, chunk, &chunk_size); - phpstr_free(s); - return chunk_size; - } - - if (storage->used >= (chunk_size = storage->size >> 1)) { - *chunk = estrndup(storage->data, chunk_size); - phpstr_cut(storage, 0, chunk_size); - return chunk_size; - } - - return 0; -} - -PHPSTR_API void phpstr_chunked_output(phpstr **s, const char *data, size_t data_len, size_t chunk_len, phpstr_passthru_func passthru, void *opaque TSRMLS_DC) -{ - char *chunk = NULL; - size_t got = 0; - - while ((got = phpstr_chunk_buffer(s, data, data_len, &chunk, chunk_len))) { - passthru(opaque, chunk, got TSRMLS_CC); - if (!chunk_len) { - /* we already got the last chunk, - and freed all resources */ - break; - } - data = NULL; - data_len = 0; - STR_SET(chunk, NULL); - } - STR_FREE(chunk); -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ - diff --git a/phpstr/phpstr.h b/phpstr/phpstr.h deleted file mode 100644 index 3a4f88b..0000000 --- a/phpstr/phpstr.h +++ /dev/null @@ -1,224 +0,0 @@ - -/* $Id$ */ - -#ifndef _PHPSTR_H_ -#define _PHPSTR_H_ - -#ifndef PHPSTR_DEFAULT_SIZE -# define PHPSTR_DEFAULT_SIZE 256 -#endif - -#define PHPSTR_NOMEM ((size_t) -1) - -#ifndef STR_FREE -# define STR_FREE(STR) \ - { \ - if (STR) { \ - efree(STR); \ - } \ - } -#endif -#ifndef STR_SET -# define STR_SET(STR, SET) \ - { \ - STR_FREE(STR); \ - STR = SET; \ - } -#endif -#ifndef TSRMLS_D -# define TSRMLS_D -# define TSRMLS_DC -# define TSRMLS_CC -# define TSRMLS_C -#endif -#ifdef PHP_ATTRIBUTE_FORMAT -# define PHPSTR_ATTRIBUTE_FORMAT(f, a, b) PHP_ATTRIBUTE_FORMAT(f, a, b) -#else -# define PHPSTR_ATTRIBUTE_FORMAT(f, a, b) -#endif -#ifndef pemalloc -# define pemalloc(s,p) malloc(s) -# define pefree(x,p) free(x) -# define perealloc(x,s,p) realloc(x,s) -# define perealloc_recoverable perealloc -# define ecalloc calloc -static inline void *estrndup(void *p, size_t s) -{ - char *r = (char *) malloc(s+1); - if (r) memcpy((void *) r, p, s), r[s] = '\0'; - return (void *) r; -} -#endif - -#if defined(PHP_WIN32) -# if defined(PHPSTR_EXPORTS) -# define PHPSTR_API __declspec(dllexport) -# elif defined(COMPILE_DL_PHPSTR) -# define PHPSTR_API __declspec(dllimport) -# else -# define PHPSTR_API -# endif -#else -# define PHPSTR_API -#endif - -#define PHPSTR(p) ((phpstr *) (p)) -#define PHPSTR_VAL(p) (PHPSTR(p))->data -#define PHPSTR_LEN(p) (PHPSTR(p))->used - -#define FREE_PHPSTR_PTR(STR) pefree(STR, STR->pmem) -#define FREE_PHPSTR_VAL(STR) phpstr_dtor(STR) -#define FREE_PHPSTR_ALL(STR) phpstr_free(&(STR)) -#define FREE_PHPSTR(free, STR) \ - switch (free) \ - { \ - case PHPSTR_FREE_NOT: break; \ - case PHPSTR_FREE_PTR: pefree(STR, STR->pmem); break; \ - case PHPSTR_FREE_VAL: phpstr_dtor(STR); break; \ - case PHPSTR_FREE_ALL: \ - { \ - phpstr *PTR = (STR); \ - phpstr_free(&PTR); \ - } \ - break; \ - default: break; \ - } - -#define RETURN_PHPSTR_PTR(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_PTR, 0) -#define RETURN_PHPSTR_VAL(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_NOT, 0) -#define RETURN_PHPSTR_DUP(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_NOT, 1) -#define RETVAL_PHPSTR_PTR(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_PTR, 0) -#define RETVAL_PHPSTR_VAL(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_NOT, 0) -#define RETVAL_PHPSTR_DUP(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_NOT, 1) -/* RETURN_PHPSTR(buf, PHPSTR_FREE_PTR, 0) */ -#define RETURN_PHPSTR(STR, free, dup) \ - RETVAL_PHPSTR((STR), (free), (dup)); \ - return; - -#define RETVAL_PHPSTR(STR, free, dup) \ - phpstr_fix(STR); \ - RETVAL_STRINGL((STR)->data, (STR)->used, (dup)); \ - FREE_PHPSTR((free), (STR)); - -typedef struct _phpstr_t { - char *data; - size_t used; - size_t free; - size_t size; - unsigned pmem:1; - unsigned reserved:31; -} phpstr; - -typedef enum _phpstr_free_t { - PHPSTR_FREE_NOT = 0, - PHPSTR_FREE_PTR, /* pefree() */ - PHPSTR_FREE_VAL, /* phpstr_dtor() */ - PHPSTR_FREE_ALL /* phpstr_free() */ -} phpstr_free_t; - -#define PHPSTR_ALL_FREE(STR) PHPSTR_FREE_ALL,(STR) -#define PHPSTR_PTR_FREE(STR) PHPSTR_FREE_PTR,(STR) -#define PHPSTR_VAL_FREE(STR) PHPSTR_FREE_VAL,(STR) -#define PHPSTR_NOT_FREE(STR) PHPSTR_FREE_NOT,(STR) - -#define PHPSTR_INIT_PREALLOC 0x01 -#define PHPSTR_INIT_PERSISTENT 0x02 - -/* create a new phpstr */ -#define phpstr_new() phpstr_init(NULL) -#define phpstr_init(b) phpstr_init_ex(b, PHPSTR_DEFAULT_SIZE, 0) -#define phpstr_clone(phpstr_pointer) phpstr_init_ex(NULL, (phpstr_pointer)->size, (phpstr_pointer)->pmem ? PHPSTR_INIT_PERSISTENT:0) -PHPSTR_API phpstr *phpstr_init_ex(phpstr *buf, size_t chunk_size, int flags); - -/* create a phpstr from a zval or c-string */ -#define phpstr_from_zval(z) phpstr_from_string(Z_STRVAL(z), Z_STRLEN(z)) -#define phpstr_from_zval_ex(b, z) phpstr_from_string_ex(b, Z_STRVAL(z), Z_STRLEN(z)) -#define phpstr_from_string(s, l) phpstr_from_string_ex(NULL, (s), (l)) -PHPSTR_API phpstr *phpstr_from_string_ex(phpstr *buf, const char *string, size_t length); - -/* usually only called from within the internal functions */ -#define phpstr_resize(b, s) phpstr_resize_ex((b), (s), 0, 0) -PHPSTR_API size_t phpstr_resize_ex(phpstr *buf, size_t len, size_t override_size, int allow_error); - -/* shrink memory chunk to actually used size (+1) */ -PHPSTR_API size_t phpstr_shrink(phpstr *buf); - -/* append data to the phpstr */ -#define phpstr_appends(b, a) phpstr_append((b), (a), sizeof(a)-1) -#define phpstr_appendl(b, a) phpstr_append((b), (a), strlen(a)) -PHPSTR_API size_t phpstr_append(phpstr *buf, const char *append, size_t append_len); -PHPSTR_API size_t phpstr_appendf(phpstr *buf, const char *format, ...) PHPSTR_ATTRIBUTE_FORMAT(printf, 2, 3); - -/* insert data at a specific position of the phpstr */ -#define phpstr_inserts(b, i, o) phpstr_insert((b), (i), sizeof(i)-1, (o)) -#define phpstr_insertl(b, i, o) phpstr_insert((b), (i), strlen(i), (o)) -PHPSTR_API size_t phpstr_insert(phpstr *buf, const char *insert, size_t insert_len, size_t offset); -PHPSTR_API size_t phpstr_insertf(phpstr *buf, size_t offset, const char *format, ...) PHPSTR_ATTRIBUTE_FORMAT(printf, 3, 4); - -/* prepend data */ -#define phpstr_prepends(b, p) phpstr_prepend((b), (p), sizeof(p)-1) -#define phpstr_prependl(b, p) phpstr_prepend((b), (p), strlen(p)) -PHPSTR_API size_t phpstr_prepend(phpstr *buf, const char *prepend, size_t prepend_len); -PHPSTR_API size_t phpstr_prependf(phpstr *buf, const char *format, ...) PHPSTR_ATTRIBUTE_FORMAT(printf, 2, 3); - -/* get a zero-terminated string */ -PHPSTR_API char *phpstr_data(const phpstr *buf, char **into, size_t *len); - -/* get a part of the phpstr */ -#define phpstr_mid(b, o, l) phpstr_sub((b), (o), (l)) -#define phpstr_left(b, l) phpstr_sub((b), 0, (l)) -PHPSTR_API phpstr *phpstr_right(const phpstr *buf, size_t length); -PHPSTR_API phpstr *phpstr_sub(const phpstr *buf, size_t offset, size_t len); - -/* remove a substring */ -PHPSTR_API size_t phpstr_cut(phpstr *buf, size_t offset, size_t length); - -/* get a complete phpstr duplicate */ -PHPSTR_API phpstr *phpstr_dup(const phpstr *buf); - -/* merge several phpstr objects - use like: - - phpstr *final = phpstr_merge(3, - PHPSTR_NOT_FREE(&keep), - PHPSTR_ALL_FREE(middle_ptr), - PHPSTR_VAL_FREE(&local); -*/ -PHPSTR_API phpstr *phpstr_merge(unsigned argc, ...); -PHPSTR_API phpstr *phpstr_merge_ex(phpstr *buf, unsigned argc, ...); -PHPSTR_API phpstr *phpstr_merge_va(phpstr *buf, unsigned argc, va_list argv); - -/* sets a trailing NUL byte */ -PHPSTR_API phpstr *phpstr_fix(phpstr *buf); - -/* memcmp for phpstr objects */ -PHPSTR_API int phpstr_cmp(phpstr *left, phpstr *right); - -/* reset phpstr object */ -PHPSTR_API void phpstr_reset(phpstr *buf); - -/* free a phpstr objects contents */ -PHPSTR_API void phpstr_dtor(phpstr *buf); - -/* free a phpstr object completely */ -PHPSTR_API void phpstr_free(phpstr **buf); - -/* stores data in a phpstr until it reaches chunk_size */ -PHPSTR_API size_t phpstr_chunk_buffer(phpstr **s, const char *data, size_t data_len, char **chunk, size_t chunk_size); - -typedef void (*phpstr_passthru_func)(void *opaque, const char *, size_t TSRMLS_DC); - -/* wrapper around phpstr_chunk_buffer, which passes available chunks to passthru() */ -PHPSTR_API void phpstr_chunked_output(phpstr **s, const char *data, size_t data_len, size_t chunk_size, phpstr_passthru_func passthru, void *opaque TSRMLS_DC); - -#endif - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ diff --git a/phpunit.php b/phpunit.php new file mode 100644 index 0000000..8a61937 --- /dev/null +++ b/phpunit.php @@ -0,0 +1,4 @@ +run(array_merge($argv, array(__DIR__."/phpunit/"))); diff --git a/phpunit/CookieTest.php b/phpunit/CookieTest.php new file mode 100644 index 0000000..d569c75 --- /dev/null +++ b/phpunit/CookieTest.php @@ -0,0 +1,204 @@ + array(), + "extras" => array(), + "flags" => 0, + "expires" => -1, + "path" => "", + "domain" => "", + "max-age" => -1, + ); + $this->assertEquals($a, $c->toArray()); + $this->assertEquals($a, $o->toArray()); + } + + function testExpiresAsDate() { + $d = new DateTime; + $c = new http\Cookie(array("expires" => $d->format(DateTime::RFC1123))); + $this->assertEquals($d->format("U"), $c->getExpires()); + } + + function testNumeric() { + $c = new http\Cookie("1=%20; 2=%22; 3=%5D", 0, array(2)); + $this->assertEquals("1=%20; 3=%5D; 2=%22; ", (string) $c); + } + + function testRaw() { + $c = new http\Cookie("1=%20; 2=%22; e3=%5D", http\Cookie::PARSE_RAW, array(2)); + $this->assertEquals("1=%2520; e3=%255D; 2=%2522; ", (string) $c); + } + + function testSimple() { + $orig = new http\Cookie("key=value"); + $copy = clone $orig; + $same = new http\Cookie($copy); + $even = new http\Cookie($same->toArray()); + foreach (array($orig, $copy) as $c) { + $this->assertEquals("value", $c->getCookie("key")); + $this->assertEquals(-1, $c->getExpires()); + $this->assertEquals(-1, $c->getMaxAge()); + $this->assertEquals(0, $c->getFlags()); + $this->assertEquals(null, $c->getPath()); + $this->assertEquals(null, $c->getDomain()); + $this->assertEquals(array(), $c->getExtras()); + $this->assertEquals(array("key" => "value"), $c->getCookies()); + $this->assertEquals("key=value; ", $c->toString()); + $this->assertEquals( + array ( + "cookies" => + array ( + "key" => "value", + ), + "extras" => + array ( + ), + "flags" => 0, + "expires" => -1, + "path" => "", + "domain" => "", + "max-age" => -1, + ), + $c->toArray() + ); + } + } + + function testExpires() { + $c = new http\Cookie("this=expires; expires=Tue, 24 Jan 2012 10:35:32 +0100"); + $this->assertEquals("expires", $c->getCookie("this")); + $this->assertEquals(1327397732, $c->getExpires()); + $o = clone $c; + $t = time(); + $o->setExpires(); + $this->assertEquals(-1, $o->getExpires()); + $this->assertNotEquals(-1, $c->getExpires()); + $o->setExpires($t); + $this->assertEquals($t, $o->getExpires()); + $this->assertNotEquals($t, $c->getExpires()); + $this->assertEquals( + sprintf( + "this=expires; expires=%s; ", + date_create("@$t") + ->setTimezone(new DateTimezone("UTC")) + ->format("D, d M Y H:i:s \\G\\M\\T") + ), + $o->toString() + ); + } + + function testMaxAge() { + $c = new http\Cookie("this=max-age; max-age=12345"); + $this->assertEquals("max-age", $c->getCookie("this")); + $this->assertEquals(12345, $c->getMaxAge()); + $o = clone $c; + $t = 54321; + $o->setMaxAge(); + $this->assertEquals(-1, $o->getMaxAge()); + $this->assertNotEquals(-1, $c->getMaxAge()); + $o->setMaxAge($t); + $this->assertEquals($t, $o->getMaxAge()); + $this->assertNotEquals($t, $c->getMaxAge()); + $this->assertEquals( + "this=max-age; max-age=$t; ", + $o->toString() + ); + } + + function testPath() { + $c = new http\Cookie("this=has a path; path=/down; "); + $this->assertEquals("has a path", $c->getCookie("this")); + $this->assertEquals("this=has%20a%20path; path=/down; ", (string)$c); + $this->assertEquals("/down", $c->getPath()); + $o = clone $c; + $p = "/up"; + $o->setPath(); + $this->assertEquals(null, $o->getPath()); + $this->assertNotEquals(null, $c->getPath()); + $o->setPath($p); + $this->assertEquals($p, $o->getPath()); + $this->assertNotEquals($p, $c->getPath()); + $this->assertEquals("this=has%20a%20path; path=$p; ", $o->toString()); + } + + function testDomain() { + $c = new http\Cookie("this=has a domain; domain=.example.com; "); + $this->assertEquals("has a domain", $c->getCookie("this")); + $this->assertEquals("this=has%20a%20domain; domain=.example.com; ", (string)$c); + $this->assertEquals(".example.com", $c->getDomain()); + $o = clone $c; + $d = "sub.example.com"; + $o->setDomain(); + $this->assertEquals(null, $o->getDomain()); + $this->assertNotEquals(null, $c->getDomain()); + $o->setDomain($d); + $this->assertEquals($d, $o->getDomain()); + $this->assertNotEquals($d, $c->getDomain()); + $this->assertEquals("this=has%20a%20domain; domain=$d; ", $o->toString()); + } + + function testFlags() { + $c = new http\Cookie("icanhas=flags; secure; httpOnly"); + $this->assertEquals(http\Cookie::SECURE, $c->getFlags() & http\Cookie::SECURE, "secure"); + $this->assertEquals(http\Cookie::HTTPONLY, $c->getFlags() & http\Cookie::HTTPONLY, "httpOnly"); + $c->setFlags($c->getFlags() ^ http\Cookie::SECURE); + $this->assertEquals(0, $c->getFlags() & http\Cookie::SECURE, "secure"); + $this->assertEquals(http\Cookie::HTTPONLY, $c->getFlags() & http\Cookie::HTTPONLY, "httpOnly"); + $c->setFlags($c->getFlags() ^ http\Cookie::HTTPONLY); + $this->assertEquals(0, $c->getFlags() & http\Cookie::SECURE, "secure"); + $this->assertEquals(0, $c->getFlags() & http\Cookie::HTTPONLY, "httpOnly"); + $this->assertEquals("icanhas=flags; ", $c->toString()); + $c->setFlags(http\Cookie::SECURE|http\Cookie::HTTPONLY); + $this->assertEquals("icanhas=flags; secure; httpOnly; ", $c->toString()); + } + + function testExtras() { + $c = new http\Cookie("c1=v1; e0=1; e2=2; c2=v2", 0, array("e0", "e1", "e2")); + $this->assertEquals(array("c1"=>"v1", "c2"=>"v2"), $c->getCookies()); + $this->assertEquals(array("e0"=>"1", "e2"=>"2"), $c->getExtras()); + $c->addExtra("e1", 1); + $c->setExtra("e0"); + $c->setExtra("e3", 123); + $this->assertEquals(123, $c->getExtra("e3")); + $c->setExtra("e3"); + $this->assertEquals(array("e2"=>"2", "e1"=>1), $c->getExtras()); + $this->assertEquals("c1=v1; c2=v2; e2=2; e1=1; ", $c->toString()); + $c->addExtras(array("e3"=>3, "e4"=>4)); + $this->assertEquals(array("e2"=>"2", "e1"=>1, "e3"=>3, "e4"=>4), $c->getExtras()); + $this->assertEquals("c1=v1; c2=v2; e2=2; e1=1; e3=3; e4=4; ", $c->toString()); + $c->setExtras(array("e"=>"x")); + $this->assertEquals(array("e"=>"x"), $c->getExtras()); + $this->assertEquals("c1=v1; c2=v2; e=x; ", $c->toString()); + $c->setExtras(); + $this->assertEquals(array(), $c->getExtras()); + $this->assertEquals("c1=v1; c2=v2; ", $c->toString()); + } + + function testCookies() { + $c = new http\Cookie("e0=1; c1=v1; e2=2; c2=v2", 0, array("c0", "c1", "c2")); + $this->assertEquals(array("c1"=>"v1", "c2"=>"v2"), $c->getExtras()); + $this->assertEquals(array("e0"=>"1", "e2"=>"2"), $c->getCookies()); + $c->addCookie("e1", 1); + $c->setCookie("e0"); + $c->setCookie("e3", 123); + $this->assertEquals(123, $c->getCookie("e3")); + $c->setCookie("e3"); + $this->assertEquals(array("e2"=>"2", "e1"=>1), $c->getCookies()); + $this->assertEquals("e2=2; e1=1; c1=v1; c2=v2; ", $c->toString()); + $c->addCookies(array("e3"=>3, "e4"=>4)); + $this->assertEquals(array("e2"=>"2", "e1"=>1, "e3"=>3, "e4"=>4), $c->getCookies()); + $this->assertEquals("e2=2; e1=1; e3=3; e4=4; c1=v1; c2=v2; ", $c->toString()); + $c->setCookies(array("e"=>"x")); + $this->assertEquals(array("e"=>"x"), $c->getCookies()); + $this->assertEquals("e=x; c1=v1; c2=v2; ", $c->toString()); + $c->setCookies(); + $this->assertEquals(array(), $c->getCookies()); + $this->assertEquals("c1=v1; c2=v2; ", $c->toString()); + } +} diff --git a/phpunit/EncodingTest.php b/phpunit/EncodingTest.php new file mode 100644 index 0000000..4642613 --- /dev/null +++ b/phpunit/EncodingTest.php @@ -0,0 +1,172 @@ +assertEquals(implode("", $file), http\Encoding\Stream\Dechunk::decode($cenc)); + } + + function testChunkNoteEncoded() { + $s = "this is apparently not encodded\n"; + $this->assertEquals($s, @http\Encoding\Stream\Dechunk::decode($s)); + } + + function testChunkNotEncodedNotice() { + error_reporting(E_ALL); + $this->setExpectedException("PHPUnit_Framework_Error_Notice", + "Data does not seem to be chunked encoded"); + $s = "this is apparently not encodded\n"; + $this->assertEquals($s, http\Encoding\Stream\Dechunk::decode($s)); + } + + function testChunkNotEncodedFail() { + $s = "3\nis \nbetter than\n1\n"; + $this->assertNotEquals($s, @http\Encoding\Stream\Dechunk::decode($s)); + } + + function testChunkNotEncodedWarning1() { + $this->setExpectedException("PHPUnit_Framework_Error_Warning", + "Expected LF at pos 8 of 20 but got 0x74"); + $s = "3\nis \nbetter than\n1\n"; + http\Encoding\Stream\Dechunk::decode($s); + } + + function testChunkNotEncodedWarning2() { + $this->setExpectedException("PHPUnit_Framework_Error_Warning", + "Expected CRLF at pos 10 of 24 but got 0x74 0x74"); + $s = "3\r\nis \r\nbetter than\r\n1\r\n"; + http\Encoding\Stream\Dechunk::decode($s); + } + + function testChunkNotEncodedWarning3() { + $this->setExpectedException("PHPUnit_Framework_Error_Warning", + "Expected chunk size at pos 6 of 27 but got trash"); + $s = "3\nis \nreally better than\n1\n"; + http\Encoding\Stream\Dechunk::decode($s); + } + + function testChunkFlush() { + $dech = new http\Encoding\Stream\Dechunk(http\Encoding\Stream::FLUSH_FULL); + $file = file(__FILE__); + $data = ""; + foreach ($file as $i => $line) { + $dech = clone $dech; + if ($i % 2) { + $data .= $dech->update(sprintf("%lx\r\n%s\r\n", strlen($line), $line)); + } else { + $data .= $dech->update(sprintf("%lx\r\n", strlen($line))); + $data .= $dech->flush(); + $data .= $dech->update($line); + $data .= $dech->flush(); + $data .= $dech->update("\r\n"); + } + $dech->flush(); + $this->assertFalse($dech->done()); + } + $data .= $dech->update("0\r\n"); + $this->assertTrue($dech->done()); + $data .= $dech->finish(); + $this->assertEquals(implode("", $file), $data); + } + + function testZlibStatic() { + $file = file_get_contents(__FILE__); + $this->assertEquals($file, + http\Encoding\Stream\Inflate::decode( + http\Encoding\Stream\Deflate::encode( + $file, http\Encoding\Stream\Deflate::TYPE_GZIP + ) + ) + ); + $this->assertEquals($file, + http\Encoding\Stream\Inflate::decode( + http\Encoding\Stream\Deflate::encode( + $file, http\Encoding\Stream\Deflate::TYPE_ZLIB + ) + ) + ); + $this->assertEquals($file, + http\Encoding\Stream\Inflate::decode( + http\Encoding\Stream\Deflate::encode( + $file, http\Encoding\Stream\Deflate::TYPE_RAW + ) + ) + ); + } + + function testZlibAutoFlush() { + $defl = new http\Encoding\Stream\Deflate(http\Encoding\Stream::FLUSH_FULL); + $infl = new http\Encoding\Stream\Inflate; + + for ($f = fopen(__FILE__, "rb"); !feof($f); $data = fread($f, 0x100)) { + $infl = clone $infl; + $defl = clone $defl; + if (isset($data)) { + $this->assertEquals($data, $infl->update($defl->update($data))); + } + } + + echo $infl->update($defl->finish()); + echo $infl->finish(); + } + + function testZlibWithoutFlush() { + $defl = new http\Encoding\Stream\Deflate; + $infl = new http\Encoding\Stream\Inflate; + $file = file(__FILE__); + $data = ""; + foreach ($file as $line) { + $infl = clone $infl; + $defl = clone $defl; + if (strlen($temp = $defl->update($line))) { + foreach(str_split($temp) as $byte) { + $data .= $infl->update($byte); + } + } + } + if (strlen($temp = $defl->finish())) { + $data .= $infl->update($temp); + } + $data .= $infl->finish(); + $this->assertEquals(implode("", $file), $data); + } + + function testZlibWithExplicitFlush() { + $defl = new http\Encoding\Stream\Deflate; + $infl = new http\Encoding\Stream\Inflate; + $file = file(__FILE__); + $data = ""; + foreach ($file as $line) { + $data .= $infl->flush(); + if (strlen($temp = $defl->update($line))) { + $data .= $infl->update($temp); + $data .= $infl->flush(); + } + if (strlen($temp = $defl->flush())) { + $data .= $infl->update($temp); + $data .= $infl->flush(); + } + $this->assertTrue($defl->done()); + } + if (strlen($temp = $defl->finish())) { + $data .= $infl->update($temp); + } + $this->assertTrue($defl->done()); + $data .= $infl->finish(); + $this->assertTrue($infl->done()); + $this->assertEquals(implode("", $file), $data); + } + + function testInflateError() { + $this->setExpectedException("PHPUnit_Framework_Error_Warning", + "Could not inflate data: data error"); + http\Encoding\Stream\Inflate::decode("if this goes through, something's pretty wrong"); + } +} diff --git a/phpunit/MessageBodyTest.php b/phpunit/MessageBodyTest.php new file mode 100644 index 0000000..3aaf3eb --- /dev/null +++ b/phpunit/MessageBodyTest.php @@ -0,0 +1,135 @@ +file = new http\Message\Body(fopen(__FILE__, "r")); + $this->temp = new http\Message\Body(); + } + + function testStat() { + $this->assertEquals(filesize(__FILE__), $this->file->stat("size")); + $this->assertEquals(filemtime(__FILE__), $this->file->stat("mtime")); + $this->assertEquals(fileatime(__FILE__), $this->file->stat("atime")); + $this->assertEquals(filectime(__FILE__), $this->file->stat("ctime")); + $this->assertEquals( + (object) array( + "size" => 0, + "mtime" => 0, + "atime" => 0, + "ctime" => 0, + ), + $this->temp->stat() + ); + } + + function testAppendError() { + $this->setExpectedException("http\Exception\RuntimeException"); + $this->file->append("nope"); + } + function testAppend() { + $this->temp->append("yes"); + } + + function testAddForm() { + $this->temp->addForm( + array( + "foo" => "bar", + "more" => array( + "bah", "baz", "fuz" + ), + ), + array( + array( + "file" => __FILE__, + "name" => "upload", + "type" => "text/plain", + ) + ) + ); + + $file = str_replace("%", "%c", file_get_contents(__FILE__)); + $this->assertStringMatchesFormat( + "--%x.%x\r\n". + "Content-Disposition: form-data; name=\"foo\"\r\n". + "\r\n". + "bar\r\n". + "--%x.%x\r\n". + "Content-Disposition: form-data; name=\"more[0]\"\r\n". + "\r\n". + "bah\r\n". + "--%x.%x\r\n". + "Content-Disposition: form-data; name=\"more[1]\"\r\n". + "\r\n". + "baz\r\n". + "--%x.%x\r\n". + "Content-Disposition: form-data; name=\"more[2]\"\r\n". + "\r\n". + "fuz\r\n". + "--%x.%x\r\n". + "Content-Disposition: form-data; name=\"upload\"; filename=\"MessageBodyTest.php\"\r\n". + "Content-Transfer-Encoding: binary\r\n". + "Content-Type: text/plain\r\n". + "\r\n". + "{$file}\r\n". + "--%x.%x--\r\n". + "", + str_replace("\r", "", $this->temp) // phpunit replaces \r\n with \n + ); + } + + function testAddPart() { + $this->temp->addPart(new http\Message("This: is a header\n\nand this is the data\n")); + $this->assertStringMatchesFormat( + "--%x.%x\r\n". + "This: is a header\r\n". + "Content-Length: 21\r\n". + "\r\n". + "and this is the data\n\r\n". + "--%x.%x--\r\n". + "", + str_replace("\r", "", $this->temp) + ); + } + + function testEtag() { + $s = stat(__FILE__); + $this->assertEquals( + sprintf( + "%lx-%lx-%lx", + $s["ino"],$s["mtime"],$s["size"] + ), + $this->file->etag() + ); + $this->assertEquals(crc32(""), $this->temp->etag()); + } + + function testToStream() { + $this->file->toStream($f = fopen("php://temp", "w")); + fseek($f, 0, SEEK_SET); + $this->assertEquals( + file_get_contents(__FILE__), + fread($f, filesize(__FILE__)) + ); + } + + function testToCallback() { + $s = ""; + $this->file->toCallback( + function($body, $string) use (&$s) { $s.=$string; } + ); + $this->assertEquals($s, (string) $this->file); + } + + function testClone() { + $this->assertEquals((string) $this->file, (string) clone $this->file); + } + + function testGetResource() { + $stream = $this->file->getResource(); + $this->assertTrue(is_resource($stream)); + $stat = fstat($stream); + $this->assertEquals(filesize(__FILE__), $stat["size"]); + } +} diff --git a/phpunit/ParamsTest.php b/phpunit/ParamsTest.php new file mode 100644 index 0000000..71bfcf4 --- /dev/null +++ b/phpunit/ParamsTest.php @@ -0,0 +1,186 @@ +runAssertions( + new http\Params($s), + str_replace(" ", "", $s) + ); + } + + function testCustom() { + $s = "foo bar.arg:0.bla gotit:0.now"; + $this->runAssertions( + new http\Params($s, " ", ".", ":"), + $s + ); + } + + function testQuoted() { + $p = new http\Params("multipart/form-data; boundary=\"--123\""); + $this->assertEquals( + array( + "multipart/form-data" => array( + "value" => true, + "arguments" => array( + "boundary" => "--123" + ) + ) + ), + $p->params + ); + $this->assertEquals("multipart/form-data;boundary=--123", (string) $p); + } + + function testEscaped() { + $p = new http\Params("form-data; name=\"upload\"; filename=\"trick\\\"\0\\\"ed\""); + $this->assertEquals( + array( + "form-data" => array( + "value" => true, + "arguments" => array( + "name" => "upload", + "filename" => "trick\"\0\"ed" + ) + ) + ), + $p->params + ); + $this->assertEquals("form-data;name=upload;filename=\"trick\\\"\\0\\\"ed\"", (string) $p); + } + + function testUrlencoded() { + $s = "foo=b%22r&bar=b%22z&a%5B%5D%5B%5D=1"; + $p = new http\Params($s, "&", "", "=", http\Params::PARSE_URLENCODED); + $this->assertEquals( + array( + "foo" => array( + "value" => "b\"r", + "arguments" => array(), + ), + "bar" => array( + "value" => "b\"z", + "arguments" => array(), + ), + "a[][]" => array( + "value" => "1", + "arguments" => array(), + ), + ), + $p->params + ); + $this->assertEquals("foo=b%22r&bar=b%22z&a%5B%5D%5B%5D=1", (string) $p); + } + + function testQuery() { + $s = "foo=b%22r&bar=b%22z&a%5B%5D%5B%5D=1"; + $p = new http\Params($s, "&", "", "=", http\Params::PARSE_QUERY); + $this->assertEquals( + array( + "foo" => array( + "value" => "b\"r", + "arguments" => array(), + ), + "bar" => array( + "value" => "b\"z", + "arguments" => array(), + ), + "a" => array( + "value" => array( + array("1") + ), + "arguments" => array(), + ), + ), + $p->params + ); + $this->assertEquals("foo=b%22r&bar=b%22z&a%5B0%5D%5B0%5D=1", (string) $p); + } + + + function testEmpty() { + $p = new http\Params(NULL); + $this->assertEquals(array(), $p->params); + } + + function testErrorOfToArrayWithArgs() { + $this->setExpectedException("PHPUnit_Framework_Error_Warning"); + $p = new http\Params(); + $p->toArray("dummy"); + } + + function testIntegerKeys() { + $p = new http\Params("0=nothing;1=yes"); + $this->assertEquals(array("0" => array("value" => "nothing", "arguments" => array(1=>"yes"))), $p->params); + $this->assertEquals("0=nothing;1=yes", $p->toString()); + } + + function testBoolParamArguments() { + $p = new http\Params; + $container = array("value" => false, "arguments" => array("wrong" => false, "correct" => true)); + $p["container"] = $container; + $this->assertEquals("container=0;wrong=0;correct", $p->toString()); + $this->assertEquals(array("container" => $container), $p->toArray()); + } + + function testNoArgsForParam() { + $p = new http\Params; + $p["param"] = true; + $this->assertEquals("param", $p->toString()); + $p["param"] = false; + $this->assertEquals("param=0", $p->toString()); + } + + protected function runAssertions($p, $s) { + $this->assertCount(3, $p->params); + $this->assertArrayHasKey("foo", $p->params); + $this->assertArrayHasKey("bar", $p->params); + $this->assertArrayHasKEy("gotit", $p->params); + + $this->assertTrue($p["foo"]["value"]); + $this->assertTrue($p["bar"]["value"]); + $this->assertEmpty($p["gotit"]["value"]); + + $this->assertEmpty($p["foo"]["arguments"]); + $this->assertCount(2, $p["bar"]["arguments"]); + $this->assertCount(1, $p["gotit"]["arguments"]); + + $this->assertEmpty($p["bar"]["arguments"]["arg"]); + $this->assertTrue($p["bar"]["arguments"]["bla"]); + $this->assertTrue($p["gotit"]["arguments"]["now"]); + + $this->assertEquals($s, (string) $p); + + $comp = array ( + 'foo' => + array ( + 'value' => true, + 'arguments' => + array ( + ), + ), + 'bar' => + array ( + 'value' => true, + 'arguments' => + array ( + 'arg' => '0', + 'bla' => true, + ), + ), + 'gotit' => + array ( + 'value' => '0', + 'arguments' => + array ( + 'now' => true, + ), + ), + ); + + $this->assertEquals($comp, $p->params); + $a = new http\Params($p->params); + $this->assertEquals($comp, $a->toArray()); + } +} diff --git a/phpunit/QueryStringTest.php b/phpunit/QueryStringTest.php new file mode 100644 index 0000000..fb2eb47 --- /dev/null +++ b/phpunit/QueryStringTest.php @@ -0,0 +1,66 @@ +q = new http\QueryString($this->s); + } + + function testSimple() { + $this->assertEquals($this->e, (string) $this->q); + $this->assertEquals($this->e, $this->q->get()); + } + + function testGetDefval() { + $this->assertEquals("nonexistant", $this->q->get("unknown", "s", "nonexistant")); + $this->assertEquals(null, $this->q->get("unknown")); + } + + function testGetA() { + $this->assertEquals("b", $this->q->get("a")); + $this->assertEquals(0, $this->q->get("a", "i")); + $this->assertEquals(array("b"), $this->q->get("a", "a")); + $this->assertEquals((object)array("scalar" => "b"), $this->q->get("a", "o")); + } + + function testGetR() { + $this->assertEquals(array(0,1,2), $this->q->get("r")); + } + + function testGetRR() { + $this->assertEquals(array(array("00","01")), $this->q->get("rr")); + } + + function testGet1() { + $this->assertEquals(2, $this->q->get(1)); + $this->assertEquals("2", $this->q->get(1, "s")); + $this->assertEquals(2.0, $this->q->get(1, "f")); + $this->assertTrue($this->q->get(1, "b")); + } + + function testDelA() { + $this->assertEquals("b", $this->q->get("a", http\QueryString::TYPE_STRING, null, true)); + $this->assertEquals(null, $this->q->get("a")); + } + + function testDelAll() { + $this->q->set(array("a" => null, "r" => null, "rr" => null, 1 => null)); + $this->assertEquals("", $this->q->toString()); + } + + function testQSO() { + $this->assertEquals($this->e, (string) new http\QueryString($this->q)); + $this->assertEquals(http_build_query(array("e"=>$this->q->toArray())), (string) new http\QueryString(array("e" => $this->q))); + } + + function testIterator() { + $this->assertEquals($this->q->toArray(), iterator_to_array($this->q)); + } + + function testSerialize() { + $this->assertEquals($this->e, (string) unserialize(serialize($this->q))); + } +} diff --git a/phpunit/UrlTest.php b/phpunit/UrlTest.php new file mode 100644 index 0000000..dcf3b4f --- /dev/null +++ b/phpunit/UrlTest.php @@ -0,0 +1,49 @@ +url = "http://user:pass@www.example.com:8080/path/file.ext". + "?foo=bar&more[]=1&more[]=2#hash"; + } + + function testStandard() { + $this->assertEquals($this->url, (string) new http\Url($this->url)); + + $url = new http\Url($this->url, + array("path" => "changed", "query" => "foo=&added=this"), + http\Url::JOIN_PATH | + http\Url::JOIN_QUERY | + http\Url::STRIP_AUTH | + http\Url::STRIP_FRAGMENT + ); + + $this->assertEquals("http", $url->scheme); + $this->assertEmpty($url->user); + $this->assertEmpty($url->pass); + $this->assertEquals("www.example.com", $url->host); + $this->assertEquals(8080, $url->port); + $this->assertEquals("/path/changed", $url->path); + $this->assertEquals("more%5B0%5D=1&more%5B1%5D=2&added=this", $url->query); + $this->assertEmpty($url->fragment); + } + + function testMod() { + $tmp = new http\Url($this->url); + $mod = $tmp->mod(array("query" => "set=1"), http\Url::REPLACE); + $this->assertNotEquals($tmp->toArray(), $mod->toArray()); + $this->assertEquals("set=1", $mod->query); + $this->assertEquals("new_fragment", $tmp->mod("#new_fragment")->fragment); + } + + function testStrings() { + $url = new http\Url($this->url); + $this->assertEquals((string) $url, (string) new http\Url((string) $url)); + } + + function testArrays() { + $url = new http\Url($this->url); + $url2 = new http\Url($url->toArray()); + $this->assertEquals($url->toArray(), $url2->toArray()); + } +} diff --git a/rebuild b/rebuild deleted file mode 100755 index e32fd35..0000000 --- a/rebuild +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -rm -f warnings - -if test -d "$1"; then - PREFIX=$1 - shift -else - PREFIX=`dirname $(dirname $(which php-config))` -fi - -echo "Using prefix '$PREFIX' for phpize and php-config!" - -echo -n "executing phpize... " -${PREFIX}/bin/phpize 2>&1 >/dev/null -if test $? -ne 0 ; then - echo "FAILED!" - exit 1 -fi -echo "DONE" - -echo -n "configuring... " -CFLAGS="-Wall -Wextra -Wno-unused-parameter -Wfloat-equal -Wdeclaration-after-statement -Wundef -Wbad-function-cast -Wcast-align -Wmissing-field-initializers -Wnested-externs" \ - ./configure --with-php-config=${PREFIX}/bin/php-config $@ >/dev/null -if test $? -ne 0 ; then - echo "FAILED!" - exit 1 -fi -echo "DONE" - -echo -n "building... " -make clean all 2>warnings >/dev/null -if test $? -ne 0 ; then - echo "FAILED!" -else - echo "DONE" -fi - -if test -s warnings; then - grep -E "^/.+http" warnings -fi - diff --git a/reflection2php.php b/reflection2php.php new file mode 100755 index 0000000..e486012 --- /dev/null +++ b/reflection2php.php @@ -0,0 +1,205 @@ +#!/usr/bin/env php +getClass()) return "\\" . $c->getName() . " "; + if ($p->isArray()) return "array "; +} +function c($n, $c) { + $_=$c; + while ($c = $c->getParentClass()) { + if (array_key_exists($n, $c->getConstants())) { + return false; + } + } + $c=$_; + foreach ((array) $c->getInterfaces() as $i) { + if (array_key_exists($n, $i->getConstants()) || !c($n, $i)) { + return false; + } + } + return true; +} + +ob_start(function($s) { + // redirect any output to stderr + fwrite(STDERR, $s); + return true; +}); + +$out = STDOUT; +switch ($argc) { + default: + case 3: + $out = fopen($argv[2], "w") or die; + case 2: + $ext = $argv[1]; + break; + + case 1: + die(sprintf($out, "Usage: %s \n", $argv[0])); +} + +fprintf($out, "getConstants() as $constant => $value) { + $ns = ($nsend = strrpos($constant, "\\")) ? substr($constant, 0, $nsend++) : ""; + $cn = substr($constant, $nsend); + $constants[$ns][$cn] = $value; +} +foreach ($ext->getFunctions() as $f) { + /* @var $f ReflectionFunction */ + $ns = $f->inNamespace() ? $f->getNamespaceName() : ""; + $functions[$ns][$f->getShortName()] = $f; +} +foreach ($ext->getClasses() as $c) { + /* @var $c ReflectionClass */ + $ns = $c->inNamespace() ? $c->getNamespaceName() : ""; + $structures[$ns][$c->getShortName()] = $c; +} + +$namespaces = array_unique(array_merge( + array_keys($constants), + array_keys($functions), + array_keys($structures) +)); + +// simple sort +natsort($namespaces); + +foreach ($namespaces as $ns) { + fprintf($out, "namespace %s%s\n{\n", $ns, strlen($ns) ? " " : ""); + // + if (isset($constants[$ns])) { + ksort($constants[$ns], SORT_NATURAL); + foreach ($constants[$ns] as $cn => $value) { + fprintf($out, "\tconst %s = %s;\n", $cn, var_export($value, true)); + } + } + // + if (isset($functions[$ns])) { + ksort($functions[$ns], SORT_NATURAL); + foreach ($functions[$ns] as $fn => $f) { + /* @var $f ReflectionFunction */ + fprintf($out, "\n\tfunction %s(", $fn); + $ps = array(); + foreach ($f->getParameters() as $p) { + $p1 = sfprintf($out, "%s%s\$%s", t($p), + $p->isPassedByReference()?"&":"", $p->getName()); + if ($p->isOptional()) { + if ($p->isDefaultValueAvailable()) { + $p1 .= sfprintf($out, " = %s", + var_export($p->getDefaultValue(), true)); + } elseif (!($p->isArray() || $p->getClass()) || $p->allowsNull()) { + $p1 .= " = NULL"; + } elseif ($p->isArray()) { + $p1 .= " = array()"; + } + } + $ps[] = $p1; + } + fprintf($out, "%s) {\n\t}\n", implode(", ", $ps)); + } + } + // + if (isset($structures[$ns])) { + uasort($structures[$ns], function ($a, $b) { + /* @var $a ReflectionClass */ + /* @var $b ReflectionClass */ + $score = array_sum([ + -!$a->isInterface()+ + -!$a->isAbstract()+ + -!$a->isTrait()+ + -!substr_compare($a->getShortName(), "Exception", -strlen("Exception")), + +!$b->isInterface()+ + +!$b->isAbstract()+ + +!$b->isTrait()+ + -!substr_compare($b->getShortName(), "Exception", -strlen("Exception")), + ]); + + if ($score) { + return -$score; + } + return strnatcmp($a->getShortName(), $b->getShortName()); + }); + foreach ($structures[$ns] as $cn => $c) { + fprintf($out, "\n\t%s%s %s ", m($c->getModifiers()), + $c->isInterface() ? "interface":"class", $c->getShortName()); + if ($p = $c->getParentClass()) { + fprintf($out, "extends \\%s ", $p->getName()); + } + if ($i = $c->getInterfaceNames()) { + fprintf($out, "implements \\%s ", + implode(", \\", array_filter($i, function($v) { + return $v != "Traversable"; + + })) + ); + } + fprintf($out, "\n\t{\n"); + + $_=0; + foreach ($c->getConstants() as $n => $v) { + c($n, $c) and $_+=fprintf($out, "\t\tconst %s = %s;\n", $n, + var_export($v, true)); + } + $_ and fprintf($out, "\n"); + $_=0; + foreach ($c->getProperties() as $p) { + if ($p->getDeclaringClass()->getName() == $c->getName()) { + $_+=fprintf($out, "\t\t%s\$%s;\n", m($p->getModifiers()), + $p->getName()); + } + } + $_ and fprintf($out, "\n"); + + foreach ($c->getMethods() as $m) { + if ($m->getDeclaringClass()->getName() == $c->getName()) { + fprintf($out, "\t\t%sfunction %s(", m($m->getModifiers()), + $m->getName()); + $ps = array(); + foreach ($m->getParameters() as $p) { + $p1 = sprintf("%s%s\$%s", t($p), + $p->isPassedByReference()?"&":"", $p->getName()); + if ($p->isOptional()) { + if ($p->isDefaultValueAvailable()) { + $p1 .= sprintf(" = %s", + var_export($p->getDefaultValue(), true)); + } elseif (!($p->isArray() || $p->getClass()) || $p->allowsNull()) { + $p1 .= sprintf(" = NULL"); + } elseif ($p->isArray()) { + $p1 .= " = array()"; + } + } + $ps[] = $p1; + } + fprintf($out, "%s)", implode(", ", $ps)); + if ($m->isAbstract()) { + fprintf($out, ";\n\n"); + } else { + fprintf($out, " {\n\t\t}\n\n"); + } + } + } + + fprintf($out, "\t}\n"); + + } + } + // + fprintf($out, "}\n\n"); +} diff --git a/scripts/bench_select_vs_event.php b/scripts/bench_select_vs_event.php deleted file mode 100644 index 589f31e..0000000 --- a/scripts/bench_select_vs_event.php +++ /dev/null @@ -1,72 +0,0 @@ -url = $url; - $pool->cnt = $n; - - $pool->enableEvents($e); - - for ($i = 0; $i < $c; ++$i) { - $pool->push(); - } - try { - $pool->send(); - } catch (Exception $ex) { - echo $ex, "\n"; - } - } - - function push() { - if ($this->cnt > 0) { - request::init($this, $this->url)->id = $this->cnt--; - } - } -} - -class request extends HttpRequest { - static $counter = 0; - - public $id; - private $pool; - - static function init(pool $pool, $url) { - $r = new request($url); - $r->pool = $pool; - $pool->attach($r); - return $r; - } - - function onFinish() { - ++self::$counter; - $this->pool->detach($this); - $this->pool->push(); - } -} - -function usage() { - global $argv; - fprintf(STDERR, "Usage: %s -u -n -c -e (use libevent)\n", $argv[0]); - fprintf(STDERR, "\nDefaults: -u http://localhost/ -n 1000 -c 10\n\n"); - exit(-1); -} - -isset($argv) or $argv = $_SERVER['argv']; -defined('STDERR') or define('STDERR', fopen('php://stderr', 'w')); - -$opts = getopt("u:c:n:e"); -isset($opts["u"]) or $opts["u"] = "http://localhost/"; -isset($opts["c"]) or $opts["c"] = 10; -isset($opts["n"]) or $opts["n"] = 1000; - -http_parse_message(http_head($opts["u"]))->responseCode == 200 or usage(); - -$time = microtime(true); -pool::fetch($opts["u"], $opts["n"], $opts["c"], isset($opts["e"])); -printf("\n> %10.6fs\n", microtime(true)-$time); - -request::$counter == $opts["n"] or printf("\nOnly %d finished\n", request::$counter); diff --git a/scripts/check_docs.php b/scripts/check_docs.php deleted file mode 100755 index c44eae7..0000000 --- a/scripts/check_docs.php +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env php -getINIEntries() as $name => $tmp) { - re("configuration.xml", "# $name #") or printf("\t%s (%s)\n", $name, $tmp); -} -printf("\n"); - -printf("Undocumented stream filters:\n"); -foreach (preg_grep("/^$ext\./", stream_get_filters()) as $filter) { - fe(sprintf("streamfilters/%s.xml", substr($filter, 5))) or printf("\t%s\n", $filter); -} -printf("\n"); - -printf("Undocumented constants:\n"); -foreach ($ref->getConstants() as $name => $tmp) { - re("constants.xml", "#$name #") or printf("\t%s (%s)\n", $name, $tmp); -} -printf("\n"); - - -printf("Undocumented functions:\n"); -foreach ($ref->getFunctions() as $func) { - /* @var $func ReflectionFunction */ - fg(sprintf("functions/*/%s.xml", strtr($func->getName(),'_','-'))) or printf("\t%s()\n", $func->getName()); -} -printf("\n"); - -printf("Undocumented classes/members:\n"); -foreach ($ref->getClasses() as $class) { - if (substr($class->getName(), -strlen("Exception")) === "Exception") continue; - /* @var $class ReflectionClass */ - fg(sprintf("%s.xml", $class->getName())) or printf(" %s\n", $class->getName()); - foreach ($class->getConstants() as $name => $tmp) { - re($class->getName().".xml", "#>$name<#") or printf("\t%s::%s (%s)\n", $class->getName(), $name, $tmp); - } - foreach ($class->getProperties() as $prop) { - /* @var $prop ReflectionProperty */ - $prop->isPrivate() or re($class->getName().".xml", "#>{$prop->getName()}<#") or printf("\t%s::$%s\n", $class->getName(), $prop->getName()); - } - foreach ($class->getMethods() as $meth) { - /* @var $meth ReflectionMethod */ - try { - $meth->getPrototype(); - } catch (Exception $ex) { - // if getPrototype throws an exception it's definitely not a method declared in an interface - $meth->isPrivate() or fg(sprintf("%s/%s.xml", $class->getName(), strtr(trim($meth->getName(),'_'),'_','-'))) or printf("\t%s%s::%s()\n", $meth->isStatic()?'static ':'', $class->getName(), $meth->getName()); - } - - } - printf("\n"); -} -printf("\n"); - -printf("Undocumented request options:\n"); -if (is_file($file = dirname(__FILE__)."/../http_request_api.c")) { - if (preg_match_all("#(?:http_request_option\(request,\s*options,\s*\")(\w+)(?=\")#", file_get_contents($file), $match)) { - foreach ($match[1] as $opt) { - re("request-options.xml", "#\s*$opt#") or printf("\t%s\n", $opt); - } - printf("\n"); - printf("List of request option entities:\n"); - foreach ($match[1] as $opt) { - printf("\t %1\$s request option'>\n", $opt); - } - } -} else { - printf("\thttp_request_api.c not found\n"); -} -printf("\n"); - -?> diff --git a/tests/HttpMessage_001.phpt b/tests/HttpMessage_001.phpt deleted file mode 100644 index ecdf228..0000000 --- a/tests/HttpMessage_001.phpt +++ /dev/null @@ -1,70 +0,0 @@ ---TEST-- -HttpMessage ---SKIPIF-- - ---FILE-- -getResponseStatus()); - -$x = $m->getParentMessage(); -$x = $m->getParentMessage(); -$x = $m->getParentMessage(); - -var_dump($m->getBody()); -var_dump(HttpMessage::fromString($m->toString(true))->toString(true)); -try { - do { - var_dump($m->toString()); - } while ($m = $m->getParentMessage()); -} catch (HttpException $ex) { -} - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -string(15) "Partial content" -string(1) "X" -string(190) "HTTP/1.1 301 -Location: /anywhere -HTTP/1.1 302 -Location: /somewhere -HTTP/1.1 206 Partial content -Content-Range: bytes=2-3 -X-Original-Transfer-Encoding: chunked -Content-Length: 1 - -X -" -string(119) "HTTP/1.1 206 Partial content -Content-Range: bytes=2-3 -X-Original-Transfer-Encoding: chunked -Content-Length: 1 - -X -" -string(36) "HTTP/1.1 302 -Location: /somewhere -" -string(35) "HTTP/1.1 301 -Location: /anywhere -" -Done diff --git a/tests/HttpMessage_002.phpt b/tests/HttpMessage_002.phpt deleted file mode 100644 index a7ad345..0000000 --- a/tests/HttpMessage_002.phpt +++ /dev/null @@ -1,65 +0,0 @@ ---TEST-- -HttpMessage properties ---SKIPIF-- - ---FILE-- -var_property); - var_dump($this->public_property); - var_dump($this->protected_property); - var_dump($this->private_property); - var_dump($this->non_ex_property); - $this->var_property.='_property'; - $this->public_property.='_property'; - $this->protected_property.='_property'; - $this->private_property.='_property'; - $this->non_ex_property = 'non_ex'; - var_dump($this->var_property); - var_dump($this->public_property); - var_dump($this->protected_property); - var_dump($this->private_property); - var_dump($this->non_ex_property); - - print_r($this->headers); - $this->headers['Foo'] = 'Bar'; - } -} - -error_reporting(E_ALL|E_STRICT); - -echo "-TEST\n"; -$m = new Message; -$m->test(); -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -string(3) "var" -string(6) "public" -string(9) "protected" -string(7) "private" - -Notice: Undefined property: Message::$non_ex_property in %s -NULL -string(12) "var_property" -string(15) "public_property" -string(18) "protected_property" -string(16) "private_property" -string(6) "non_ex" -Array -( -) -%aFatal error%sCannot access HttpMessage properties by reference or array key/index in%s diff --git a/tests/HttpMessage_003.phpt b/tests/HttpMessage_003.phpt deleted file mode 100644 index 831b4da..0000000 --- a/tests/HttpMessage_003.phpt +++ /dev/null @@ -1,70 +0,0 @@ ---TEST-- -HttpMessage implements Serializable, Countable ---SKIPIF-- - ---FILE-- -count()); -var_dump($m->serialize()); -$m->unserialize("HTTP/1.1 200 Ok\r\nServer: Funky/1.0"); -var_dump($m); -var_dump($m->count()); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -int(3) -string(148) "HTTP/1.1 301 -Location: /anywhere -HTTP/1.1 302 -Location: /somewhere -HTTP/1.1 200 -X-Original-Transfer-Encoding: chunked -Content-Length: 1 - -X -" -object(HttpMessage)#%d (%d) { - ["type%s]=> - int(2) - ["body%s]=> - string(0) "" - ["requestMethod%s]=> - string(0) "" - ["requestUrl%s]=> - string(0) "" - ["responseStatus%s]=> - string(2) "Ok" - ["responseCode%s]=> - int(200) - ["httpVersion%s]=> - float(1.1) - ["headers%s]=> - array(1) { - ["Server"]=> - string(9) "Funky/1.0" - } - ["parentMessage%s]=> - NULL -} -int(1) -Done diff --git a/tests/HttpMessage_004.phpt b/tests/HttpMessage_004.phpt deleted file mode 100644 index 6324233..0000000 --- a/tests/HttpMessage_004.phpt +++ /dev/null @@ -1,36 +0,0 @@ ---TEST-- -HttpMessage::detach() ---SKIPIF-- - ---FILE-- -detach(); -$d->addHeaders(array('Server'=>'Funky/2.0')); -var_dump($d->getHeaders() == $m->getHeaders()); -var_dump($d->getBody()); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -bool(false) -string(3) "Hi!" -Done \ No newline at end of file diff --git a/tests/HttpMessage_005.phpt b/tests/HttpMessage_005.phpt deleted file mode 100644 index 81dd7dd..0000000 --- a/tests/HttpMessage_005.phpt +++ /dev/null @@ -1,86 +0,0 @@ ---TEST-- -HttpMessage::prepend() ---SKIPIF-- - ---FILE-- -prepend($m2); -$m2 = NULL; -echo $m1->toString(true); - -$m1->prepend($m1->detach(), false); -echo $m1->toString(true); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -GET http://example.com/ HTTP/1.0 -HTTP/1.1 200 ok -Server: Funky/2.0 -Content-Type: text/html -Content-Length: 9 - -Hi there! -GET / HTTP/1.1 -Host: example.com -Accept: */* -Connection: close -HTTP/1.1 200 ok -Server: Funky/1.0 -Content-Type: text/plain -Content-Length: 3 - -Hi! -GET http://example.com/ HTTP/1.0 -HTTP/1.1 200 ok -Server: Funky/2.0 -Content-Type: text/html -Content-Length: 9 - -Hi there! -GET / HTTP/1.1 -Host: example.com -Accept: */* -Connection: close -HTTP/1.1 200 ok -Server: Funky/1.0 -Content-Type: text/plain -Content-Length: 3 - -Hi! -HTTP/1.1 200 ok -Server: Funky/1.0 -Content-Type: text/plain -Content-Length: 3 - -Hi! -Done \ No newline at end of file diff --git a/tests/HttpMessage_006.phpt b/tests/HttpMessage_006.phpt deleted file mode 100644 index c7363ce..0000000 --- a/tests/HttpMessage_006.phpt +++ /dev/null @@ -1,35 +0,0 @@ ---TEST-- -HttpMessage iterator ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -== -HTTP/1.1 304 Not Modified -== -GET /foo HTTP/1.1 -== -HTTP/1.1 200 OK -== -GET / HTTP/1.1 -Done \ No newline at end of file diff --git a/tests/HttpMessage_008.phpt b/tests/HttpMessage_008.phpt deleted file mode 100644 index 66e41dc..0000000 --- a/tests/HttpMessage_008.phpt +++ /dev/null @@ -1,41 +0,0 @@ ---TEST-- -HttpMessage::toMessageTypeObject() ---SKIPIF-- - ---FILE-- -"b",1=>2),null); - -$m = new HttpMessage; -$m->setType(HttpMessage::TYPE_REQUEST); -$m->setRequestMethod('POST'); -$m->setRequestUrl("http://www.example.com"); -$m->setHttpVersion('1.1'); -$m->addHeaders( - array( - "Content-Type" => "application/x-www-form-urlencoded", - "Host" => "www.example.com", - "Content-Length"=> strlen($b), - ) -); -$m->setBody($b); -$r = $m->toMessageTypeObject(); -echo $m,"\n"; -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -POST http://www.example.com HTTP/1.1 -Content-Type: application/x-www-form-urlencoded -Host: www.example.com -Content-Length: 7 - -a=b&1=2 - -Done diff --git a/tests/HttpMessage_009_bug16700.phpt b/tests/HttpMessage_009_bug16700.phpt deleted file mode 100644 index 4c25eb7..0000000 --- a/tests/HttpMessage_009_bug16700.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -Bug #16700 - child classes of HttpMessage cannot not have array properties ---SKIPIF-- - ---FILE-- -properties['foo'] = 'bar'; -echo $child->properties['foo'], "\n"; -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -bar -Done diff --git a/tests/HttpQueryString_001.phpt b/tests/HttpQueryString_001.phpt deleted file mode 100644 index b329429..0000000 --- a/tests/HttpQueryString_001.phpt +++ /dev/null @@ -1,116 +0,0 @@ ---TEST-- -HttpQueryString global ---SKIPIF-- - ---FILE-- -'b','c'=>'3.4','r'=>array(1,2,3)); -$_SERVER['QUERY_STRING'] = 'a=b&c=3.4&r[0]=1&r[1]=2&r[2]=3'; - -var_dump(HttpQueryString::singleton()->get()); -var_dump(HttpQueryString::singleton()->get('n')); -var_dump(HttpQueryString::singleton()->get('a')); -var_dump(HttpQueryString::singleton()->get('a', "i", 0, true)); -var_dump(HttpQueryString::singleton()->get('a', "string", 'hi!')); -var_dump(HttpQueryString::singleton()->get('c')); -var_dump(HttpQueryString::singleton()->get('c', HttpQueryString::TYPE_INT)); -var_dump(HttpQueryString::singleton()->get('c', HttpQueryString::TYPE_FLOAT)); -var_dump(HttpQueryString::singleton()->get('c', HttpQueryString::TYPE_BOOL)); -var_dump(HttpQueryString::singleton()->get('r')); -var_dump(HttpQueryString::singleton()->get('r', HttpQueryString::TYPE_ARRAY)); -var_dump(HttpQueryString::singleton()->get('r', HttpQueryString::TYPE_OBJECT)); - -HttpQueryString::singleton()->set(new HttpQueryString(false, 'z[0]=2')); - -HttpQueryString::singleton()->set(array('a'=>'b', 'c'=> "3.4")); -HttpQueryString::singleton()->set(array('a' => NULL)); - -var_dump(HttpQueryString::singleton()); -var_dump($_GET); -var_dump($_SERVER['QUERY_STRING']); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -string(42) "a=b&c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3" -NULL -string(1) "b" -int(0) -string(3) "hi!" -string(3) "3.4" -int(3) -float(3.4) -bool(true) -array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) -} -array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) -} -object(stdClass)#%d (%d) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) -} -object(HttpQueryString)#1 (2) { - ["queryArray%s]=> - &array(3) { - ["c"]=> - string(3) "3.4" - ["r"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["z"]=> - array(1) { - [0]=> - string(1) "2" - } - } - ["queryString%s]=> - &string(49) "c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3&z%5B0%5D=2" -} -array(3) { - ["c"]=> - string(3) "3.4" - ["r"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["z"]=> - array(1) { - [0]=> - string(1) "2" - } -} -string(49) "c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3&z%5B0%5D=2" -Done \ No newline at end of file diff --git a/tests/HttpQueryString_002.phpt b/tests/HttpQueryString_002.phpt deleted file mode 100644 index f70cbac..0000000 --- a/tests/HttpQueryString_002.phpt +++ /dev/null @@ -1,108 +0,0 @@ ---TEST-- -HttpQueryString local ---SKIPIF-- - ---FILE-- -'b','c'=>'3.4','r'=>array(1,2,3))); -var_dump($q->get()); -var_dump($q->get('n')); -var_dump($q->get('a')); -var_dump($q->get('a', "i", 0, true)); -var_dump($q->get('a', "string", 'hi!')); -var_dump($q->get('c')); -var_dump($q->get('c', HttpQueryString::TYPE_INT)); -var_dump($q->get('c', HttpQueryString::TYPE_FLOAT)); -var_dump($q->get('c', HttpQueryString::TYPE_BOOL)); -var_dump($q->get('r')); -var_dump($q->get('r', HttpQueryString::TYPE_ARRAY)); -var_dump($q->get('r', HttpQueryString::TYPE_OBJECT)); - -$q->set('z[0]=2'); -$q->set(array('a'=>'b', 'c'=> "3.4")); -$q->set(array('a' => NULL)); - -var_dump($q); -var_dump($array); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -string(42) "a=b&c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3" -NULL -string(1) "b" -int(0) -string(3) "hi!" -string(3) "3.4" -int(3) -float(3.4) -bool(true) -array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) -} -array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) -} -object(stdClass)#%d (%d) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) -} -object(HttpQueryString)#1 (2) { - ["queryArray%s]=> - array(3) { - ["c"]=> - string(3) "3.4" - ["r"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["z"]=> - array(1) { - [0]=> - string(1) "2" - } - } - ["queryString%s]=> - string(49) "c=3.4&r%5B0%5D=1&r%5B1%5D=2&r%5B2%5D=3&z%5B0%5D=2" -} -array(3) { - ["a"]=> - string(1) "b" - ["c"]=> - string(3) "3.4" - ["r"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } -} -Done \ No newline at end of file diff --git a/tests/HttpQueryString_003.phpt b/tests/HttpQueryString_003.phpt deleted file mode 100644 index 6342ad6..0000000 --- a/tests/HttpQueryString_003.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -HttpQueryString xlate ---SKIPIF-- - ---FILE-- -get()); -$qs->xlate("latin1", "utf8"); -var_dump($qs->get()); -$qs->xlate("utf8", "latin1"); -var_dump($qs->get()); -echo "Done\n"; ---EXPECTF-- -%aTEST -string(29) "%E4%5B0%5D=%FC&%F6%5Ba%5D=%DF" -string(41) "%C3%A4%5B0%5D=%C3%BC&%C3%B6%5Ba%5D=%C3%9F" -string(29) "%E4%5B0%5D=%FC&%F6%5Ba%5D=%DF" -Done diff --git a/tests/HttpQueryString_004.phpt b/tests/HttpQueryString_004.phpt deleted file mode 100644 index 66d7ec5..0000000 --- a/tests/HttpQueryString_004.phpt +++ /dev/null @@ -1,54 +0,0 @@ ---TEST-- -HttpQueryString w/ objects ---SKIPIF-- - ---FILE-- -bar = (object) array("baz"=>1); - $this->dont_show = 'xxx'; - $this->dont_show2 = 'zzz'; - } -} -$foo = new test_props; -var_dump($q = new HttpQueryString(false, $foo)); -$foo->bar->baz = 0; -var_dump($q->mod($foo)); -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -object(HttpQueryString)#3 (2) { - ["queryArray%s]=> - array(1) { - ["bar"]=> - array(1) { - ["baz"]=> - int(1) - } - } - ["queryString%s]=> - string(14) "bar%5Bbaz%5D=1" -} -object(HttpQueryString)#4 (2) { - ["queryArray%s]=> - array(1) { - ["bar"]=> - array(1) { - ["baz"]=> - int(0) - } - } - ["queryString%s]=> - string(14) "bar%5Bbaz%5D=0" -} -Done diff --git a/tests/HttpRequestDataShare_001.phpt b/tests/HttpRequestDataShare_001.phpt deleted file mode 100644 index 728fe0d..0000000 --- a/tests/HttpRequestDataShare_001.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -HttpRequestDataShare ---SKIPIF-- - ---FILE-- -dns = true; -$s->cookie = true; - -$r1 = new HttpRequest("http://www.google.com/"); -$r2 = new HttpRequest("http://www.google.com/"); - -$r1->enableCookies(); -$r2->enableCookies(); - -$s->attach($r1); -$s->attach($r2); - -$r1->send(); -$r2->send(); - -$s->reset(); - -var_dump(current($r1->getResponseCookies())->cookies["PREF"] === HttpUtil::parseCookie($r2->getRequestMessage()->getHeader("Cookie"))->cookies["PREF"]); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -bool(true) -Done diff --git a/tests/HttpRequestDataShare_002.phpt b/tests/HttpRequestDataShare_002.phpt deleted file mode 100644 index 9bd2a18..0000000 --- a/tests/HttpRequestDataShare_002.phpt +++ /dev/null @@ -1,52 +0,0 @@ ---TEST-- -HttpRequestDataShare global ---SKIPIF-- - ---FILE-- -cookie = true; -var_dump($s); - -$r1 = new HttpRequest("http://www.google.com/"); -$r2 = new HttpRequest("http://www.google.com/"); - -$r1->enableCookies(); -$r2->enableCookies(); - -$s->attach($r1); -$s->attach($r2); - -$r1->send(); -$r2->send(); - -$s->reset(); - -if (current($r1->getResponseCookies())->cookies["PREF"] !== HttpUtil::parseCookie($r2->getRequestMessage()->getHeader("Cookie"))->cookies["PREF"]) { - var_dump( - current($r1->getResponseCookies())->cookies["PREF"], - HttpUtil::parseCookie($r2->getRequestMessage()->getHeader("Cookie"))->cookies["PREF"] - ); -} - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -object(HttpRequestDataShare)#1 (4) { - ["cookie"]=> - bool(true) - ["dns"]=> - bool(true) - ["ssl"]=> - bool(false) - ["connect"]=> - bool(false) -} -Done diff --git a/tests/HttpRequestPool_001.phpt b/tests/HttpRequestPool_001.phpt deleted file mode 100644 index c0d9c94..0000000 --- a/tests/HttpRequestPool_001.phpt +++ /dev/null @@ -1,51 +0,0 @@ ---TEST-- -HttpRequestPool ---SKIPIF-- - ---FILE-- -addPostFields(array('a'=>1,'b'=>2)) ; - -$pool = new HttpRequestPool( - new HttpRequest('http://www.php.net/', HTTP_METH_HEAD), - $post -); - -$pool->send(); - -foreach ($pool as $req) { - echo $req->getUrl(), '=', - $req->getResponseCode(), ':', - $req->getResponseMessage()->getResponseCode(), "\n"; -} - -foreach ($pool as $req) { - try { - $pool->attach(new HttpRequest('http://foo.bar')); - } catch (HttpRequestPoolException $x) { - echo ".\n"; - } -} - -foreach ($pool as $req) { - $pool->detach($req); -} - -echo "Done\n"; -?> - ---EXPECTF-- -%aTEST -http://www.php.net/=200:200 -http://dev.iworks.at/ext-http/.print_request.php=200:200 -. -. -Done diff --git a/tests/HttpRequestPool_002.phpt b/tests/HttpRequestPool_002.phpt deleted file mode 100644 index 94fd2c5..0000000 --- a/tests/HttpRequestPool_002.phpt +++ /dev/null @@ -1,51 +0,0 @@ ---TEST-- -extending HttpRequestPool ---SKIPIF-- - ---FILE-- -socketPerform()) { - if (!$this->socketSelect()) { - throw new HttpSocketException; - } - } - } - - protected final function socketPerform() - { - $result = parent::socketPerform(); - - echo "."; - foreach ($this->getFinishedRequests() as $r) { - echo "=", $r->getResponseCode(), "="; - $this->detach($r); - } - - return $result; - } -} - -$pool = new MyPool( - new HttpRequest('http://www.php.net/', HTTP_METH_HEAD), - new HttpRequest('http://www.php.net/', HTTP_METH_HEAD), - new HttpRequest('http://www.php.net/', HTTP_METH_HEAD) -); - -$pool->send(); - -echo "\nDone\n"; -?> ---EXPECTREGEX-- -.+TEST -\.*=200=\.*=200=\.*=200= -Done diff --git a/tests/HttpRequestPool_003.phpt b/tests/HttpRequestPool_003.phpt deleted file mode 100644 index b08a706..0000000 --- a/tests/HttpRequestPool_003.phpt +++ /dev/null @@ -1,175 +0,0 @@ ---TEST-- -HttpRequestPool chain ---SKIPIF-- - ---FILE-- -dir = (is_dir($cache_dir) or @mkdir($cache_dir)) ? $cache_dir : null; - - foreach (array_map('trim', file($urls_file)) as $url) { - $this->all[$url] = $this->dir ? $this->dir .'/'. md5($url) : null; - } - - $this->send(); - } - - public final function send() - { - if (RMAX) { - $now = array_slice($this->all, 0, RMAX); - $this->rem = array_slice($this->all, RMAX); - } else { - $now = $urls; - $this->rem = array(); - } - - foreach ($now as $url => $file) { - $this->attach( - new HttpRequest( - $url, - HttpRequest::METH_GET, - array( - 'redirect' => 5, - 'compress' => GZIP, - 'timeout' => TOUT, - 'connecttimeout' => TOUT, - 'lastmodified' => is_file($file)?filemtime($file):0 - ) - ) - ); - } - - while ($this->socketPerform()) { - if (!$this->socketSelect()) { - throw new HttpSocketException; - } - } - } - - protected final function socketPerform() - { - try { - $rc = parent::socketPerform(); - } catch (HttpRequestException $x) { - // a request may have thrown an exception, - // but it is still save to continue - echo $x->getMessage(), "\n"; - } - - foreach ($this->getFinishedRequests() as $r) { - $this->detach($r); - - $u = $r->getUrl(); - $c = $r->getResponseCode(); - $b = $r->getResponseBody(); - - printf("%d %s %d\n", $c, $u, strlen($b)); - - if ($c == 200 && $this->dir) { - file_put_contents($this->all[$u], $b); - } - - if ($a = each($this->rem)) { - list($url, $file) = $a; - $this->attach( - new HttpRequest( - $url, - HttpRequest::METH_GET, - array( - 'redirect' => 5, - 'compress' => GZIP, - 'timeout' => TOUT, - 'connecttimeout' => TOUT, - 'lastmodified' => is_file($file)?filemtime($file):0 - ) - ) - ); - } - } - return $rc; - } -} - -define('GZIP', true); -define('TOUT', 50); -define('RMAX', 10); -chdir(dirname(__FILE__)); - -$time = microtime(true); -$pool = new Pool(); -printf("Elapsed: %0.3fs\n", microtime(true)-$time); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -Elapsed: %fs -Done diff --git a/tests/HttpRequestPool_004.phpt b/tests/HttpRequestPool_004.phpt deleted file mode 100644 index 69635fa..0000000 --- a/tests/HttpRequestPool_004.phpt +++ /dev/null @@ -1,19 +0,0 @@ ---TEST-- -HttpRequestPool::__destruct() invalid curl handle ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -Done diff --git a/tests/HttpRequestPool_005.phpt b/tests/HttpRequestPool_005.phpt deleted file mode 100644 index 4770fe7..0000000 --- a/tests/HttpRequestPool_005.phpt +++ /dev/null @@ -1,46 +0,0 @@ ---TEST-- -HttpRequestPool exception ---SKIPIF-- - ---FILE-- -send(); -} catch (HttpRequestPoolException $x) { - for ($i=0; $x; ++$i, $x = @$x->innerException) { - printf("%s%s: %s\n", str_repeat("\t", $i), get_class($x), $x->getMessage()); - } - var_dump($i); -} -$p = new HttpRequestPool(new HttpRequest('http://_____'), new HttpRequest('http://_____')); -try { - $p->send(); -} catch (HttpRequestPoolException $x) { - for ($i=0; $x; ++$i, $x = @$x->innerException) { - printf("%s%s: %s\n", str_repeat("\t", $i), get_class($x), $x->getMessage()); - } - var_dump($i); -} -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -HttpRequestPoolException: Exception caused by 2 inner exception(s) - HttpInvalidParamException: Empty or too short HTTP message: '' - HttpRequestException: %souldn't resolve host name; %s (http://_____/) -int(3) -HttpRequestPoolException: Exception caused by 4 inner exception(s) - HttpInvalidParamException: Empty or too short HTTP message: '' - HttpRequestException: %souldn't resolve host name; %s (http://_____/) - HttpInvalidParamException: Empty or too short HTTP message: '' - HttpRequestException: %souldn't resolve host name; %s (http://_____/) -int(5) -Done - diff --git a/tests/HttpRequestPool_006.phpt b/tests/HttpRequestPool_006.phpt deleted file mode 100644 index 043c208..0000000 --- a/tests/HttpRequestPool_006.phpt +++ /dev/null @@ -1,50 +0,0 @@ ---TEST-- -HttpRequestPool detaching in callbacks ---SKIPIF-- - ---FILE-- -getUrl()])) { - $i[$this->getUrl()] = true; - try { - $GLOBALS['p']->detach($this); - } catch (Exception $ex) { - echo $ex, "\n"; - } - } - } - function onFinish() { - $GLOBALS['p']->detach($this); - } -} -$p = new HttpRequestPool(new r("http://at.php.net"), new r("http://de.php.net")); -$p->send(); -var_dump($p->getAttachedRequests()); -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -exception 'HttpRequestPoolException' with message 'HttpRequest object(#%d) cannot be detached from the HttpRequestPool while executing the progress callback' in %aHttpRequestPool_006.php:%d -Stack trace: -#0 %aHttpRequestPool_006.php(%d): HttpRequestPool->detach(Object(r)) -#1 [internal function]: r->onProgress(Array) -#2 %aHttpRequestPool_006.php(%d): HttpRequestPool->send() -#3 {main} -exception 'HttpRequestPoolException' with message 'HttpRequest object(#%d) cannot be detached from the HttpRequestPool while executing the progress callback' in %aHttpRequestPool_006.php:%d -Stack trace: -#0 %aHttpRequestPool_006.php(%d): HttpRequestPool->detach(Object(r)) -#1 [internal function]: r->onProgress(Array) -#2 %aHttpRequestPool_006.php(%d): HttpRequestPool->send() -#3 {main} -array(0) { -} -Done diff --git a/tests/HttpRequestPool_007.phpt b/tests/HttpRequestPool_007.phpt deleted file mode 100644 index b1acafc..0000000 --- a/tests/HttpRequestPool_007.phpt +++ /dev/null @@ -1,166 +0,0 @@ ---TEST-- -HttpRequestPool chain with libevent ---SKIPIF-- - ---FILE-- -pool->detach($this); - - $u = $this->getUrl(); - $c = $this->getResponseCode(); - $b = $this->getResponseBody(); - - printf("%d %s %d\n", $c, $u, strlen($b)); - - if ($c == 200 && $this->pool->dir) { - file_put_contents($this->pool->all[$u], $b); - } - - if ($a = each($this->pool->rem)) { - list($url, $file) = $a; - $r = new Request( - $url, - HttpRequest::METH_GET, - array( - 'redirect' => 5, - 'compress' => GZIP, - 'timeout' => TOUT, - 'connecttimeout' => TOUT, - 'lastmodified' => is_file($file)?filemtime($file):0 - ) - ); - $r->pool = $this->pool; - $this->pool->attach($r); - } - } - -} - -class Pool extends HttpRequestPool -{ - public $all; - public $rem; - public $dir; - - public final function __construct($urls_file = 'urls.txt', $cache_dir = 'HttpRequestPool_cache') - { - $this->dir = (is_dir($cache_dir) or @mkdir($cache_dir)) ? $cache_dir : null; - - $urls = file($urls_file); - shuffle($urls); - foreach (array_map('trim', $urls) as $url) { - $this->all[$url] = $this->dir ? $this->dir .'/'. md5($url) : null; - } - - if (RMAX) { - $now = array_slice($this->all, 0, RMAX); - $this->rem = array_slice($this->all, RMAX); - } else { - $now = $urls; - $this->rem = array(); - } - - $this->enableEvents(); - - foreach ($now as $url => $file) { - $r = new Request( - $url, - HttpRequest::METH_GET, - array( - 'redirect' => 5, - 'compress' => GZIP, - 'timeout' => TOUT, - 'connecttimeout' => TOUT, - 'lastmodified' => is_file($file)?filemtime($file):0 - ) - ); - $r->pool = $this; - $this->attach($r); - } - - $this->send(); - } -} - -define('GZIP', true); -define('TOUT', 50); -define('RMAX', 10); -chdir(dirname(__FILE__)); - -$time = microtime(true); -$pool = new Pool(); -printf("Elapsed: %0.3fs\n", microtime(true)-$time); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -Elapsed: %fs -Done diff --git a/tests/HttpRequest_001.phpt b/tests/HttpRequest_001.phpt deleted file mode 100644 index 5ef2d9d..0000000 --- a/tests/HttpRequest_001.phpt +++ /dev/null @@ -1,51 +0,0 @@ ---TEST-- -HttpRequest options ---SKIPIF-- - ---FILE-- -11, 'headers'=>array('X-Foo'=>'Bar'))); -$r2 = new HttpRequest; -$r2->setOptions(array('redirect'=>99, 'headers'=>array('X-Bar'=>'Foo'))); -$o1 = $r1->getOptions(); -$o2 = $r2->getOptions(); -$r1->setOptions($o2); -$r2->setOptions($o1); -print_r(array($o1, $o2)); -var_dump(serialize($r1->getOptions()) === serialize($r2->getOptions())); -$r1 = null; -$r2 = null; -?> ---EXPECTF-- -%aTEST -Array -( - [0] => Array - ( - [headers] => Array - ( - [X-Foo] => Bar - [X-Bar] => Foo - ) - - [redirect] => 11 - ) - - [1] => Array - ( - [headers] => Array - ( - [X-Bar] => Foo - [X-Foo] => Bar - ) - - [redirect] => 99 - ) - -) -bool(false) diff --git a/tests/HttpRequest_002.phpt b/tests/HttpRequest_002.phpt deleted file mode 100644 index 736df23..0000000 --- a/tests/HttpRequest_002.phpt +++ /dev/null @@ -1,86 +0,0 @@ ---TEST-- -HttpRequest GET/POST ---SKIPIF-- - ---FILE-- -send(); -print_r($r->getResponseInfo()); - -$r = new HttpRequest('http://dev.iworks.at/ext-http/.print_request.php', HTTP_METH_POST); -$r->addCookies(array('MyCookie' => 'foobar')); -$r->addQueryData(array('gq'=>'foobar','gi'=>10)); -$r->addPostFields(array('pq'=>'foobar','pi'=>10)); -$r->addPostFile('upload', dirname(__FILE__).'/data.txt', 'text/plain'); -$r->send(); -echo $r->getResponseBody(); -var_dump($r->getResponseMessage()->getResponseCode()); - -echo "Done"; -?> ---EXPECTF-- -%aTEST -Array -( - [effective_url] => http://www.google.com/ - [response_code] => 302 - [total_time] => %f - [namelookup_time] => %f - [connect_time] => %f - [pretransfer_time] => %f - [size_upload] => %d - [size_download] => %d - [speed_download] => %d - [speed_upload] => %d - [header_size] => %d - [request_size] => %d - [ssl_verifyresult] => %d - [filetime] => -1 - [content_length_download] => %d - [content_length_upload] => %d - [starttransfer_time] => %f - [content_type] => %s - [redirect_time] => %d - [redirect_count] => %d - [connect_code] => %d - [httpauth_avail] => %d - [proxyauth_avail] => %d - [os_errno] => %d - [num_connects] => %d - [ssl_engines] => Array - %a - [cookies] => Array - %a - [error] => -) -Array -( - [gq] => foobar - [gi] => 10 - [pq] => foobar - [pi] => 10 - [MyCookie] => foobar -) -Array -( - [upload] => Array - ( - [name] => data.txt - [type] => text/plain - [tmp_name] => %a - [error] => 0 - [size] => 1010 - ) - -) -int(200) -Done diff --git a/tests/HttpRequest_003.phpt b/tests/HttpRequest_003.phpt deleted file mode 100644 index 723091a..0000000 --- a/tests/HttpRequest_003.phpt +++ /dev/null @@ -1,54 +0,0 @@ ---TEST-- -HttpRequest SSL ---SKIPIF-- - ---FILE-- - '3', 'ssl' => array('version' => '3', 'verifyhost' => '1')); -$r = new HttpRequest('https://ssl.irmler.at/iworks/data.txt'); -$r->setOptions($o); -$r->send(); -var_dump($r->getResponseBody()); -var_dump(is_object($r->getResponseMessage())); -var_dump(is_object($r->getResponseMessage())); -var_dump(is_object($r->getResponseMessage())); -var_dump($o); -$r->setOptions($o); -$r->send(); -var_dump($o); -?> ---EXPECTF-- -%aTEST -string(10) "1234567890" -bool(true) -bool(true) -bool(true) -array(2) { - ["redirect"]=> - string(1) "3" - ["ssl"]=> - array(2) { - ["version"]=> - string(1) "3" - ["verifyhost"]=> - string(1) "1" - } -} -array(2) { - ["redirect"]=> - string(1) "3" - ["ssl"]=> - array(2) { - ["version"]=> - string(1) "3" - ["verifyhost"]=> - string(1) "1" - } -} - diff --git a/tests/HttpRequest_004.phpt b/tests/HttpRequest_004.phpt deleted file mode 100644 index 313a4dc..0000000 --- a/tests/HttpRequest_004.phpt +++ /dev/null @@ -1,162 +0,0 @@ ---TEST-- -HttpRequest multiple posts ---SKIPIF-- - ---FILE-- - 1, 'dbl' => M_PI), - array('str' => 'something', 'nil' => null) -); - -echo "\nFirst Request\n"; -$r = new HttpRequest('http://dev.iworks.at/ext-http/.print_request.php', HttpRequest::METH_POST); -$r->setPostFields($fields[0]); -$r->addPostFields($fields[1]); -var_dump($r->send()->getBody()); -var_dump($fields); - -echo "\nSecond Request\n"; -$r->setPostFields($fields); -var_dump($r->send()->getBody()); -var_dump($fields); - -echo "\nThird Request\n"; -$r->addPostFields(array('x' => 'X')); -var_dump($r->send()->getBody()); -var_dump($fields); - -echo "\nFourth Request\n"; -$r->setPostFields(array()); -var_dump($r->send()->getBody()); -var_dump($fields); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST - -First Request -string(%d) "Array -( - [int] => 1 - [dbl] => 3.1415926535898 - [str] => something - [nil] => -) -string(44) "int=1&dbl=3.1415926535898&str=something&nil=" -" -array(2) { - [0]=> - array(2) { - ["int"]=> - int(1) - ["dbl"]=> - float(3.1415926535898) - } - [1]=> - array(2) { - ["str"]=> - string(9) "something" - ["nil"]=> - NULL - } -} - -Second Request -string(%d) "Array -( - [0] => Array - ( - [int] => 1 - [dbl] => 3.1415926535898 - ) - - [1] => Array - ( - [str] => something - [nil] => - ) - -) -string(72) "0%5Bint%5D=1&0%5Bdbl%5D=3.1415926535898&1%5Bstr%5D=something&1%5Bnil%5D=" -" -array(2) { - [0]=> - array(2) { - ["int"]=> - int(1) - ["dbl"]=> - float(3.1415926535898) - } - [1]=> - array(2) { - ["str"]=> - string(9) "something" - ["nil"]=> - NULL - } -} - -Third Request -string(%d) "Array -( - [0] => Array - ( - [int] => 1 - [dbl] => 3.1415926535898 - ) - - [1] => Array - ( - [str] => something - [nil] => - ) - - [x] => X -) -string(76) "0%5Bint%5D=1&0%5Bdbl%5D=3.1415926535898&1%5Bstr%5D=something&1%5Bnil%5D=&x=X" -" -array(2) { - [0]=> - array(2) { - ["int"]=> - int(1) - ["dbl"]=> - float(3.1415926535898) - } - [1]=> - array(2) { - ["str"]=> - string(9) "something" - ["nil"]=> - NULL - } -} - -Fourth Request -string(13) "string(0) "" -" -array(2) { - [0]=> - array(2) { - ["int"]=> - int(1) - ["dbl"]=> - float(3.1415926535898) - } - [1]=> - array(2) { - ["str"]=> - string(9) "something" - ["nil"]=> - NULL - } -} -Done - diff --git a/tests/HttpRequest_005.phpt b/tests/HttpRequest_005.phpt deleted file mode 100644 index 0e78984..0000000 --- a/tests/HttpRequest_005.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -HttpRequest accessors ---SKIPIF-- - ---FILE-- - 3 && substr($method, 0, 3) == 'get') - $x = $r->$method(); - } catch (HttpException $e) { - } -} -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -Done diff --git a/tests/HttpRequest_006.phpt b/tests/HttpRequest_006.phpt deleted file mode 100644 index 44afcde..0000000 --- a/tests/HttpRequest_006.phpt +++ /dev/null @@ -1,147 +0,0 @@ ---TEST-- -HttpRequest XMLRPC ---SKIPIF-- - ---FILE-- -setContentType('text/xml'); -$r->setBody(xmlrpc_encode_request('testMethod', array('foo' => 'bar'))); -var_dump($r->send()); -var_dump($r->send()); -var_dump($r->send()); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -object(HttpMessage)#%d (%d) { - ["type:protected"]=> - int(2) - ["body:protected"]=> - string(309) "string(294) " -- -" -" - ["requestMethod:protected"]=> - string(0) "" - ["requestUrl:protected"]=> - string(0) "" - ["responseStatus:protected"]=> - string(2) "OK" - ["responseCode:protected"]=> - int(200) - ["httpVersion:protected"]=> - float(1.1) - ["headers:protected"]=> - array(6) { - %a - } - ["parentMessage:protected"]=> - NULL -} -object(HttpMessage)#%d (%d) { - ["type:protected"]=> - int(2) - ["body:protected"]=> - string(309) "string(294) " -testMethod -- - -- - -- -- -foo -- -bar -- -" -" - ["requestMethod:protected"]=> - string(0) "" - ["requestUrl:protected"]=> - string(0) "" - ["responseStatus:protected"]=> - string(2) "OK" - ["responseCode:protected"]=> - int(200) - ["httpVersion:protected"]=> - float(1.1) - ["headers:protected"]=> - array(6) { - %a - } - ["parentMessage:protected"]=> - NULL -} -object(HttpMessage)#%d (%d) { - ["type:protected"]=> - int(2) - ["body:protected"]=> - string(309) "string(294) " -testMethod -- - -- - -- -- -foo -- -bar -- -" -" - ["requestMethod:protected"]=> - string(0) "" - ["requestUrl:protected"]=> - string(0) "" - ["responseStatus:protected"]=> - string(2) "OK" - ["responseCode:protected"]=> - int(200) - ["httpVersion:protected"]=> - float(1.1) - ["headers:protected"]=> - array(6) { - %a - } - ["parentMessage:protected"]=> - NULL -} -Done diff --git a/tests/HttpRequest_007.phpt b/tests/HttpRequest_007.phpt deleted file mode 100644 index 8989de1..0000000 --- a/tests/HttpRequest_007.phpt +++ /dev/null @@ -1,64 +0,0 @@ ---TEST-- -HttpRequest PUT ---SKIPIF-- - ---FILE-- -recordHistory = true; -$r->addHeaders(array('content-type' => 'text/plain')); -$r->setPutFile(__FILE__); -$r->send(); -var_dump($r->getHistory()->toString(true)); -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -string(%d) "PUT /ext-http/.print_put.php5 HTTP/1.1 -User-Agent: PECL::HTTP/%a -Host: dev.iworks.at -Accept: */* -Content-Type: text/plain -Content-Length: %d -Expect: 100-continue - -recordHistory = true; -$r->addHeaders(array('content-type' => 'text/plain')); -$r->setPutFile(__FILE__); -$r->send(); -var_dump($r->getHistory()->toString(true)); -echo "Done\n"; -?> - -HTTP/1.1 100 Continue -HTTP/1.1 200 OK -Date: %a -Server: %a -Vary: Accept-Encoding -Content-Type: text/html -X-Original-Transfer-Encoding: chunked -Content-Length: %d - -recordHistory = true; -$r->addHeaders(array('content-type' => 'text/plain')); -$r->setPutFile(__FILE__); -$r->send(); -var_dump($r->getHistory()->toString(true)); -echo "Done\n"; -?> - -" -Done diff --git a/tests/HttpRequest_008.phpt b/tests/HttpRequest_008.phpt deleted file mode 100644 index 81dbcb3..0000000 --- a/tests/HttpRequest_008.phpt +++ /dev/null @@ -1,32 +0,0 @@ ---TEST-- -HttpRequest custom request method ---SKIPIF-- - ---FILE-- -setContentType('text/plain'); -$r->setBody('Yep, this is FOOBAR!'); -var_dump($r->send()->getResponseCode()); -var_dump($r->getRawRequestMessage()); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -int(200) -string(%d) "FOOBAR /ext-http/.print_request.php HTTP/1.1 -User-Agent: %a -Host: dev.iworks.at -Accept: */* -Content-Type: text/plain -Content-Length: 20 - -Yep, this is FOOBAR!" -Done diff --git a/tests/HttpRequest_009.phpt b/tests/HttpRequest_009.phpt deleted file mode 100644 index bbc2ddf..0000000 --- a/tests/HttpRequest_009.phpt +++ /dev/null @@ -1,48 +0,0 @@ ---TEST-- -HttpRequest callbacks ---SKIPIF-- - ---FILE-- -getResponseCode()); - } -} - -$r = new _R('http://dev.iworks.at/ext-http/.print_request.php', HTTP_METH_POST); -$r->addPostFile('upload', __FILE__, 'text/plain'); -$r->send(); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -Array -( - [dltotal] => %f - [dlnow] => %f - [ultotal] => %f - [ulnow] => %f -) -%array -( - [dltotal] => %f - [dlnow] => %f - [ultotal] => %f - [ulnow] => %f -) -int(200) -Done diff --git a/tests/HttpRequest_010.phpt b/tests/HttpRequest_010.phpt deleted file mode 100644 index ed3ca71..0000000 --- a/tests/HttpRequest_010.phpt +++ /dev/null @@ -1,48 +0,0 @@ ---TEST-- -HttpRequest cookie API ---SKIPIF-- - ---FILE-- -send(); -$c[0] = $r->getResponseInfo("cookies"); -if (!empty($c[0])) { - var_dump('$c[0]', $c[0]); -} - -var_dump($r->enableCookies()); -$r->send(); - -$c[1] = $r->getResponseInfo("cookies"); -if (empty($c[1])) { - var_dump('$c[1]', $c[1]); -} - -var_dump($r->resetCookies()); -$r->send(); - -$c[2] = $r->getResponseInfo("cookies"); -if ($c[1] === $c[2]) { - var_dump('$c[1]', $c[1], '$c[2]', $c[2]); -} - -$r->send(); -$c[3] = $r->getResponseInfo("cookies"); -if ($c[2] !== $c[3]) { - var_dump('$c[2]', $c[2], '$c[3]', $c[3]); -} - -echo "Done\n"; ---EXPECTF-- -%aTEST -bool(true) -bool(true) -Done diff --git a/tests/HttpResponse_001.phpt b/tests/HttpResponse_001.phpt deleted file mode 100644 index 58fcf21..0000000 --- a/tests/HttpResponse_001.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -HttpResponse - send data with caching headers ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: public, must-revalidate, max-age=3600 -Last-Modified: %a, %d %a 20%d %d:%d:%d GMT -Content-Type: %a -Accept-Ranges: bytes -ETag: "3858f62230ac3c915f300c664312c63f" -Content-Length: 6 - -foobar diff --git a/tests/HttpResponse_002.phpt b/tests/HttpResponse_002.phpt deleted file mode 100644 index bbfa30f..0000000 --- a/tests/HttpResponse_002.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -HttpResponse - send gzipped file ---SKIPIF-- - ---ENV-- -HTTP_ACCEPT_ENCODING=gzip ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Content-Type: %a -Accept-Ranges: bytes -Content-Encoding: gzip -Vary: Accept-Encoding - -%a diff --git a/tests/HttpResponse_003.phpt b/tests/HttpResponse_003.phpt deleted file mode 100644 index e128865..0000000 --- a/tests/HttpResponse_003.phpt +++ /dev/null @@ -1,30 +0,0 @@ ---TEST-- -HttpResponse - send gzipped file with caching headers ---SKIPIF-- - ---ENV-- -HTTP_ACCEPT_ENCODING=gzip ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: public, must-revalidate, max-age=3600 -Last-Modified: %a, %d %a 20%d %d:%d:%d GMT -Content-Type: %a -Accept-Ranges: bytes -ETag: "%a" -Content-Encoding: gzip -Vary: Accept-Encoding - -%a diff --git a/tests/HttpResponse_004.phpt b/tests/HttpResponse_004.phpt deleted file mode 100644 index 2c88b60..0000000 --- a/tests/HttpResponse_004.phpt +++ /dev/null @@ -1,27 +0,0 @@ ---TEST-- -HttpResponse - send cached gzipped data ---SKIPIF-- - ---ENV-- -HTTP_IF_NONE_MATCH="900150983cd24fb0d6963f7d28e17f72" -HTTP_ACCEPT_ENCODING=gzip ---FILE-- - ---EXPECTF-- -Status: 304%s -X-Powered-By: PHP/%s -Cache-Control: public, must-revalidate, max-age=3600 -Last-Modified: %s -Accept-Ranges: bytes -ETag: "900150983cd24fb0d6963f7d28e17f72" diff --git a/tests/HttpResponse_005.phpt b/tests/HttpResponse_005.phpt deleted file mode 100644 index bda3aa6..0000000 --- a/tests/HttpResponse_005.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -HttpResponse file not found ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -Status: 404%s -X-Powered-By: PHP/%s -Content-Type: text/plain - -File not found diff --git a/tests/allowed_methods_002.phpt b/tests/allowed_methods_002.phpt deleted file mode 100644 index 993f92e..0000000 --- a/tests/allowed_methods_002.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -allowed methods ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -Status: 405%s -X-Powered-By: PHP/%a -Allow: POST -Content-type: %a - diff --git a/tests/allowed_methods_002_logging.phpt b/tests/allowed_methods_002_logging.phpt deleted file mode 100644 index 53a2b81..0000000 --- a/tests/allowed_methods_002_logging.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -logging allowed methods ---SKIPIF-- - ---ENV-- -HTTP_HOST=example.com ---FILE-- - ---EXPECTF-- -%aTEST -%d%d%d%d-%d%d-%d%d %d%d:%d%d:%d%d [405-ALLOWED] Allow: POST <%a> -Done diff --git a/tests/bug61444.phpt b/tests/bug61444.phpt new file mode 100644 index 0000000..28d267c --- /dev/null +++ b/tests/bug61444.phpt @@ -0,0 +1,38 @@ +--TEST-- +. become _ in query strings due to php_default_treat_data() +--SKIPIF-- + +--FILE-- + 'utm_source=changed'), http\Url::JOIN_QUERY), PHP_EOL, PHP_EOL; + +// Replacing the host +echo new http\Url($url, array('host' => 'www.google.com')), PHP_EOL, PHP_EOL; + +// Generating a query string from scratch +echo new http\QueryString(array( + 'bar.baz' => 'blah', + 'utm_source' => 'google', + 'utm_campaign' => 'somethingelse', + 'blat' => null, + )), PHP_EOL, PHP_EOL; +?> +DONE +--EXPECT-- +http://www.example.com/foobar?bar.baz=blah&utm_source=google&utm_campaign=somethingelse&blat + +http://www.example.com/foobar?bar.baz=blah&utm_source=changed&utm_campaign=somethingelse + +http://www.google.com/foobar?bar.baz=blah&utm_source=google&utm_campaign=somethingelse&blat + +bar.baz=blah&utm_source=google&utm_campaign=somethingelse + +DONE diff --git a/tests/bug_15800.phpt b/tests/bug_15800.phpt deleted file mode 100644 index fad5b40..0000000 --- a/tests/bug_15800.phpt +++ /dev/null @@ -1,49 +0,0 @@ ---TEST-- -Bug #15800 Double free when zval is separated in convert_to_* ---SKIPIF-- - ---FILE-- - array('verifypeer'=>'1')); -debug_zval_dump($o); - -$r = new HttpRequest('http://www.google.com'); -$r->setOptions($o); -$r->send(); -debug_zval_dump($o); - -unset($r); -debug_zval_dump($o); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -array(1) refcount(2){ - ["ssl"]=> - array(1) refcount(1){ - ["verifypeer"]=> - string(1) "1" refcount(1) - } -} -array(1) refcount(2){ - ["ssl"]=> - array(1) refcount(1){ - ["verifypeer"]=> - string(1) "1" refcount(3) - } -} -array(1) refcount(2){ - ["ssl"]=> - array(1) refcount(1){ - ["verifypeer"]=> - string(1) "1" refcount(1) - } -} -Done diff --git a/tests/build_str_001.phpt b/tests/build_str_001.phpt deleted file mode 100644 index 8e2ce39..0000000 --- a/tests/build_str_001.phpt +++ /dev/null @@ -1,30 +0,0 @@ ---TEST-- -http_build_str ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -a=b -a=b&c%5B0%5D=1 -a=b&c%5B0%5D=1&d%5Be%5D=f -foo%5B0%5D=1&foo%5B1%5D=2&foo%5B2%5D%5B0%5D=3 -Done diff --git a/tests/build_url_001.phpt b/tests/build_url_001.phpt deleted file mode 100644 index c8b5ad3..0000000 --- a/tests/build_url_001.phpt +++ /dev/null @@ -1,18 +0,0 @@ ---TEST-- -http_build_url() with relative paths ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -http://%a/page -http://%a/with/some/path/ -Done diff --git a/tests/build_url_002.phpt b/tests/build_url_002.phpt deleted file mode 100644 index 787b7f4..0000000 --- a/tests/build_url_002.phpt +++ /dev/null @@ -1,30 +0,0 @@ ---TEST-- -http_build_url() with parse_url() ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -https://www.example.com:9999/replaced?q=1#n -https://www.example.com:9999/replaced?q=1#n -Array -( - [scheme] => https - [host] => www.example.com - [port] => 9999 - [path] => /replaced - [query] => q=1 - [fragment] => n -) -Done diff --git a/tests/build_url_003.phpt b/tests/build_url_003.phpt deleted file mode 100644 index 1736ca6..0000000 --- a/tests/build_url_003.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -http_build_url() ---SKIPIF-- - ---ENV-- -HTTP_HOST=www.example.com ---FILE-- - 'https'))); -printf("-%s-\n", http_build_url($url, array('scheme' => 'https', 'host' => 'ssl.example.com'))); -printf("-%s-\n", http_build_url($url, array('scheme' => 'ftp', 'host' => 'ftp.example.com', 'port' => 21))); -echo "Done\n"; -?> ---EXPECTF-- -%aTEST --http://www.example.com/path/?query#anchor- --https://www.example.com/path/?query#anchor- --https://ssl.example.com/path/?query#anchor- --ftp://ftp.example.com/path/?query#anchor- -Done diff --git a/tests/build_url_004.phpt b/tests/build_url_004.phpt deleted file mode 100644 index 1db54a8..0000000 --- a/tests/build_url_004.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -http_build_url flags ---SKPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -http://www.example.com/foo/baz -http://www.example.com/foo/baz -http://mike@www.example.com/foo/baz -http://www.example.com/?a%5B0%5D=1&a%5B1%5D=b&b=c -Done diff --git a/tests/chunked_decode_001.phpt b/tests/chunked_decode_001.phpt deleted file mode 100644 index 3d65dbf..0000000 --- a/tests/chunked_decode_001.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -http_chunked_decode() "\r\n" ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -string(12) "abra -cadabra" - diff --git a/tests/chunked_decode_002.phpt b/tests/chunked_decode_002.phpt deleted file mode 100644 index 3444932..0000000 --- a/tests/chunked_decode_002.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -http_chunked_decode() "\n" ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -string(12) "abra -cadabra" - diff --git a/tests/chunked_decode_003.phpt b/tests/chunked_decode_003.phpt deleted file mode 100644 index c9da8c2..0000000 --- a/tests/chunked_decode_003.phpt +++ /dev/null @@ -1,27 +0,0 @@ ---TEST-- -http_chunked_decode() truncated message ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -%aWarning%ahttp_chunked_decode()%aTruncated message: chunk size 255 exceeds remaining data size 12 at pos 34 of 46 in%a -string(24) "abra -cadabra -all we got -" diff --git a/tests/chunked_decode_004.phpt b/tests/chunked_decode_004.phpt deleted file mode 100644 index 5dc7157..0000000 --- a/tests/chunked_decode_004.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -http_chunked_decode() truncated message ending with NUL after a chunk ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -string(24) "abra -cadabra -all we got -" diff --git a/tests/client001.phpt b/tests/client001.phpt new file mode 100644 index 0000000..8071afa --- /dev/null +++ b/tests/client001.phpt @@ -0,0 +1,21 @@ +--TEST-- +client drivers +--SKIPIF-- + +--FILE-- + +Done +--EXPECTREGEX-- +Test +(?:bool\(true\) +)+Done diff --git a/tests/client002.phpt b/tests/client002.phpt new file mode 100644 index 0000000..44ff3d1 --- /dev/null +++ b/tests/client002.phpt @@ -0,0 +1,37 @@ +--TEST-- +client observer +--SKIPIF-- + +--FILE-- +getProgressInfo($request) != $progress) { + var_dump($progress); + } + } +} + +$observer = new Observer; +$request = new http\Client\Request("GET", "http://www.example.org/"); + +foreach (http\Client::getAvailableDrivers() as $driver) { + $client = new http\Client($driver); + $client->attach($observer); + $client->enqueue($request); + $client->send(); +} + +?> + +Done +--EXPECTREGEX-- +Test +P+ +Done diff --git a/tests/client003.phpt b/tests/client003.phpt new file mode 100644 index 0000000..b09c299 --- /dev/null +++ b/tests/client003.phpt @@ -0,0 +1,29 @@ +--TEST-- +client once & wait +--SKIPIF-- + +--FILE-- +enqueue($request); + + while ($client->once()) { + $client->wait(.1); + } + + if (!$client->getResponse()) { + var_dump($client); + } +} +?> +Done +--EXPECT-- +Test +Done diff --git a/tests/client004.phpt b/tests/client004.phpt new file mode 100644 index 0000000..22ad9fe --- /dev/null +++ b/tests/client004.phpt @@ -0,0 +1,35 @@ +--TEST-- +client reset +--SKIPIF-- + +--FILE-- +enqueue($request)->send(); + if (!($client->getResponse($request) instanceof http\Client\Response)) { + var_dump($client); + } + try { + $client->enqueue($request); + } catch (Exception $e) { + echo $e->getMessage(),"\n"; + } + $client->reset(); + if (($response = $client->getResponse())) { + var_dump($response); + } + $client->enqueue($request); +} +?> +Done +--EXPECTREGEX-- +Test +(?:Failed to enqueue request; request already in queue +)+Done diff --git a/tests/client005.phpt b/tests/client005.phpt new file mode 100644 index 0000000..36a3f0a --- /dev/null +++ b/tests/client005.phpt @@ -0,0 +1,27 @@ +--TEST-- +client response callback +--SKIPIF-- + +--FILE-- +enqueue(new http\Client\Request("GET", "http://www.example.org"), function($response) { + echo "R\n"; + if (!($response instanceof http\Client\Response)) { + var_dump($response); + } + }); + $client->send(); +} + +?> +Done +--EXPECTREGEX-- +Test +(?:R +)+Done diff --git a/tests/client006.phpt b/tests/client006.phpt new file mode 100644 index 0000000..762e044 --- /dev/null +++ b/tests/client006.phpt @@ -0,0 +1,42 @@ +--TEST-- +client response callback + dequeue +--SKIPIF-- + +--FILE-- +enqueue($request, "response"); + $client->send(); + try { + $client->dequeue($request); + } catch (Exception $e) { + echo $e->getMessage(),"\n"; + } + } +} + +?> +Done +--EXPECTREGEX-- +Test +(?:(?:R +Failed to dequeue request; request not in queue +)+)+Done diff --git a/tests/client007.phpt b/tests/client007.phpt new file mode 100644 index 0000000..8421b51 --- /dev/null +++ b/tests/client007.phpt @@ -0,0 +1,34 @@ +--TEST-- +client response callback + requeue +--SKIPIF-- + +--FILE-- +requeue($request, "response"); + $client->send(); + } +} + +?> +Done +--EXPECTREGEX-- +Test +(?:R +R +)+Done diff --git a/tests/client008.phpt b/tests/client008.phpt new file mode 100644 index 0000000..d7fe358 --- /dev/null +++ b/tests/client008.phpt @@ -0,0 +1,36 @@ +--TEST-- +client features +--SKIPIF-- + +--FILE-- +enablePipelining(true); + $client->enableEvents(true); + + $client->enqueue($request); + $client->enqueue(clone $request); + $client->enqueue(clone $request); + + $client->send(); + + while ($client->getResponse()) { + echo "R\n"; + } +} + +?> +Done +--EXPECTREGEX-- +Test +(?:R +R +R +)+Done diff --git a/tests/client009.phpt b/tests/client009.phpt new file mode 100644 index 0000000..937045d --- /dev/null +++ b/tests/client009.phpt @@ -0,0 +1,47 @@ +--TEST-- +client static cookies +--SKIPIF-- + +--FILE-- +setCookies(array("test" => "bar")); + $client->addCookies(array("foo" => "test")); + $client->enqueue($request); + $client->send(); + var_dump($client->getResponse()->getBody()->toString()); + $request->setOptions(array("cookies" => x($client->getCookies()))); + $client->requeue($request); + $client->send(); + var_dump($client->getResponse()->getBody()->toString()); +} + +?> +Done +--EXPECTREGEX-- +Test +(?:string\(46\) "Array +\( + \[test\] \=\> bar + \[foo\] \=\> test +\) +" +string\(46\) "Array +\( + \[test\] \=\> test + \[foo\] \=\> bar +\) +" +)+Done diff --git a/tests/client010.phpt b/tests/client010.phpt new file mode 100644 index 0000000..7563a77 --- /dev/null +++ b/tests/client010.phpt @@ -0,0 +1,36 @@ +--TEST-- +client upload +--SKIPIF-- + +--FILE-- +getBody()->addForm(null, array("file"=>__FILE__, "name"=>"upload", "type"=>"text/plain")); + +foreach (http\Client::getAvailableDrivers() as $driver) { + $client = new http\Client($driver); + $client->enqueue($request)->send(); + var_dump($client->getResponse()->getBody()->toString()); +} +?> +Done +--EXPECTREGEX-- +Test +(?:string\(\d+\) "Array +\( + \[upload\] \=\> Array + \( + \[name\] \=\> client010\.php + \[type\] \=\> text\/plain + \[tmp_name\] \=\> .* + \[error\] \=\> 0 + \[size\] \=\> \d+ + \) + +\) +" +)+Done diff --git a/tests/client011.phpt b/tests/client011.phpt new file mode 100644 index 0000000..188b178 --- /dev/null +++ b/tests/client011.phpt @@ -0,0 +1,90 @@ +--TEST-- +client history +--SKIPIF-- + +--FILE-- +append("foobar"); + +$request = new http\Client\Request; +$request->setBody($body); +$request->setRequestMethod("POST"); +$request->setRequestUrl("http://dev.iworks.at/ext-http/.print_request.php"); + +$client = new http\Client; +$client->recordHistory = true; + +$client->enqueue($request)->send(); +echo $client->getHistory()->toString(true); + +$client->requeue($request)->send(); +echo $client->getHistory()->toString(true); + +?> +Done +--EXPECTF-- +Test +POST /ext-http/.print_request.php HTTP/1.1 +User-Agent: %s +Host: dev.iworks.at +Accept: */* +Content-Length: 6 +Content-Type: application/x-www-form-urlencoded +X-Original-Content-Length: 6 + +foobar +HTTP/1.1 200 OK +Date: %s +Server: %s +Vary: %s +Content-Length: 19 +Content-Type: text/html +X-Original-Content-Length: 19 + +string(6) "foobar" + +POST /ext-http/.print_request.php HTTP/1.1 +User-Agent: %s +Host: dev.iworks.at +Accept: */* +Content-Length: 6 +Content-Type: application/x-www-form-urlencoded +X-Original-Content-Length: 6 + +foobar +HTTP/1.1 200 OK +Date: %s +Server: %s +Vary: %s +Content-Length: 19 +Content-Type: text/html +X-Original-Content-Length: 19 + +string(6) "foobar" + +POST /ext-http/.print_request.php HTTP/1.1 +User-Agent: %s +Host: dev.iworks.at +Accept: */* +Content-Length: 6 +Content-Type: application/x-www-form-urlencoded +X-Original-Content-Length: 6 + +foobar +HTTP/1.1 200 OK +Date: %s +Server: %s +Vary: %s +Content-Length: 19 +Content-Type: text/html +X-Original-Content-Length: 19 + +string(6) "foobar" + +Done diff --git a/tests/client012.phpt b/tests/client012.phpt new file mode 100644 index 0000000..71e5081 --- /dev/null +++ b/tests/client012.phpt @@ -0,0 +1,36 @@ +--TEST-- +client ssl +--SKIPIF-- + +--FILE-- +setSslOptions(array("verify_peer" => true)); +$client->addSslOptions(array("verify_host" => 2)); +var_dump( + array( + "verify_peer" => true, + "verify_host" => 2, + ) === $client->getSslOptions() +); + +$client->enqueue($req = new http\Client\Request("GET", "https://twitter.com/")); +$client->send(); + +$ti = (array) $client->getTransferInfo($req); +var_dump(array_key_exists("ssl_engines", $ti)); +var_dump(0 < count($ti["ssl_engines"])); +?> +Done +--EXPECTF-- +Test +bool(true) +bool(true) +bool(true) +Done diff --git a/tests/client013.phpt b/tests/client013.phpt new file mode 100644 index 0000000..0de0547 --- /dev/null +++ b/tests/client013.phpt @@ -0,0 +1,66 @@ +--TEST-- +client observers +--SKIPIF-- + +--FILE-- +getProgressInfo($r)) $c->pi .= "-"; + } +} +class ProgressObserver2 implements SplObserver { + function update(SplSubject $c, $r = null) { + if ($c->getProgressInfo($r)) $c->pi .= "."; + } +} +class CallbackObserver implements SplObserver { + public $callback; + function __construct($callback) { + $this->callback = $callback; + } + function update(SplSubject $c, $r = null) { + call_user_func($this->callback, $c, $r); + } +} + +$client = new Client; +$client->attach($o1 = new ProgressObserver1); +$client->attach($o2 = new ProgressObserver2); +$client->attach( + $o3 = new CallbackObserver( + function ($c, $r) { + $p = (array) $c->getProgressInfo($r); + var_dump(array_key_exists("started", $p)); + var_dump(array_key_exists("finished", $p)); + var_dump(array_key_exists("dlnow", $p)); + var_dump(array_key_exists("ulnow", $p)); + var_dump(array_key_exists("dltotal", $p)); + var_dump(array_key_exists("ultotal", $p)); + var_dump(array_key_exists("info", $p)); + } + ) +); + +$client->enqueue(new http\Client\Request("GET", "http://dev.iworks.at/ext-http/"))->send(); +var_dump(1 === preg_match("/(\.-)+/", $client->pi)); +var_dump(3 === count($client->getObservers())); +$client->detach($o1); +var_dump(2 === count($client->getObservers())); +$client->detach($o2); +var_dump(1 === count($client->getObservers())); +$client->detach($o3); +var_dump(0 === count($client->getObservers())); + +?> +Done +--EXPECTREGEX-- +Test\n(bool\(true\)\n)+Done diff --git a/tests/clientrequest001.phpt b/tests/clientrequest001.phpt new file mode 100644 index 0000000..48c863e --- /dev/null +++ b/tests/clientrequest001.phpt @@ -0,0 +1,32 @@ +--TEST-- +client request +--SKIPIF-- + +--FILE-- +getBody()); +var_dump($h === $r->getHeaders()); +var_dump($u === $r->getRequestUrl()); +var_dump($m === $r->getRequestMethod()); + +?> +Done +--EXPECT-- +Test +bool(true) +bool(true) +bool(true) +bool(true) +Done diff --git a/tests/clientrequest002.phpt b/tests/clientrequest002.phpt new file mode 100644 index 0000000..dd82337 --- /dev/null +++ b/tests/clientrequest002.phpt @@ -0,0 +1,22 @@ +--TEST-- +client request content type +--SKIPIF-- + +--FILE-- +setContentType($ct = "text/plain; charset=utf-8")); +var_dump($ct === $r->getContentType()); + +?> +Done +--EXPECT-- +Test +bool(true) +bool(true) +Done diff --git a/tests/clientrequest003.phpt b/tests/clientrequest003.phpt new file mode 100644 index 0000000..5d11e09 --- /dev/null +++ b/tests/clientrequest003.phpt @@ -0,0 +1,30 @@ +--TEST-- +client request query +--SKIPIF-- + +--FILE-- +getQuery()); +var_dump($r === $r->setQuery($q = "foo=bar")); +var_dump($q === $r->getQuery()); +var_dump($r === $r->addQuery("a[]=1&a[]=2")); +var_dump("foo=bar&a%5B0%5D=1&a%5B1%5D=2" === $r->getQuery()); +var_dump(null === $r->setQuery(null)->getQuery()); + +?> +Done +--EXPECT-- +Test +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +Done diff --git a/tests/clientrequest004.phpt b/tests/clientrequest004.phpt new file mode 100644 index 0000000..f00ee2e --- /dev/null +++ b/tests/clientrequest004.phpt @@ -0,0 +1,31 @@ +--TEST-- +client request options +--SKIPIF-- + +--FILE-- +setOptions($o = array("redirect"=>5, "timeout"=>5))); +var_dump($o === $r->getOptions()); +var_dump($r === $r->setOptions(array("timeout"=>50))); +$o["timeout"] = 50; +var_dump($o === $r->getOptions()); +var_dump($r === $r->setSslOptions($o = array("verify_peer"=>false))); +var_dump($o === $r->getSslOptions()); + +?> +Done +--EXPECT-- +Test +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +Done diff --git a/tests/clientresponse001.phpt b/tests/clientresponse001.phpt new file mode 100644 index 0000000..2f25291 --- /dev/null +++ b/tests/clientresponse001.phpt @@ -0,0 +1,45 @@ +--TEST-- +client response cookie +--SKIPIF-- + +--FILE-- +enqueue($request)->send()->getResponse()->getCookies(0, array("comment")) as $cookies) { + var_dump($cookies->toArray()); + } +} +?> +Done +--EXPECTREGEX-- +Test +(?:array\(7\) \{ + \["cookies"\]\=\> + array\(2\) \{ + \["foo"\]\=\> + string\(3\) "bar" + \["bar"\]\=\> + string\(3\) "foo" + \} + \["extras"\]\=\> + array\(0\) \{ + \} + \["flags"\]\=\> + int\(0\) + \["expires"\]\=\> + int\(\-1\) + \["max\-age"\]\=\> + int\(\-1\) + \["path"\]\=\> + string\(0\) "" + \["domain"\]\=\> + string\(0\) "" +\} +)+Done diff --git a/tests/clientresponse002.phpt b/tests/clientresponse002.phpt new file mode 100644 index 0000000..3a0c50a --- /dev/null +++ b/tests/clientresponse002.phpt @@ -0,0 +1,63 @@ +--TEST-- +client response cookies +--SKIPIF-- + +--FILE-- +enqueue($request)->send()->getResponse()->getCookies(0, array("comment")) as $cookies) { + var_dump($cookies->toArray()); + } +} +?> +Done +--EXPECTREGEX-- +Test +(?:array\(7\) \{ + \["cookies"\]\=\> + array\(1\) \{ + \["temp"\]\=\> + string\(1[23]\) "\d+\.\d+" + \} + \["extras"\]\=\> + array\(0\) \{ + \} + \["flags"\]\=\> + int\(0\) + \["expires"\]\=\> + int\(\-1\) + \["max\-age"\]\=\> + int\(\-1\) + \["path"\]\=\> + string\(0\) "" + \["domain"\]\=\> + string\(0\) "" +\} +array\(7\) \{ + \["cookies"\]\=\> + array\(1\) \{ + \["perm"\]\=\> + string\(1[23]\) "\d+\.\d+" + \} + \["extras"\]\=\> + array\(0\) \{ + \} + \["flags"\]\=\> + int\(0\) + \["expires"\]\=\> + int\(\d+\) + \["max\-age"\]\=\> + int\(\-1\) + \["path"\]\=\> + string\(0\) "" + \["domain"\]\=\> + string\(0\) "" +\} +)+Done diff --git a/tests/clientresponse003.phpt b/tests/clientresponse003.phpt new file mode 100644 index 0000000..20dcef2 --- /dev/null +++ b/tests/clientresponse003.phpt @@ -0,0 +1,25 @@ +--TEST-- +client response transfer info +--SKIPIF-- + +--FILE-- +enqueue($request)->send()->getResponse(); + var_dump($response->getTransferInfo("response_code")); + var_dump(count((array)$response->getTransferInfo())); +} +?> +Done +--EXPECTREGEX-- +Test +(?:int\([1-5]\d\d\) +int\(\d\d\) +)+Done diff --git a/tests/cloning_001.phpt b/tests/cloning_001.phpt deleted file mode 100644 index 9d26682..0000000 --- a/tests/cloning_001.phpt +++ /dev/null @@ -1,29 +0,0 @@ ---TEST-- -cloning ---SKIPIF-- - ---FILE-- -setOptions(array('redirect' => 3)); -var_dump($r1->getOptions() == $r2->getOptions()); -$r1->setUrl('http://www.google.com/'); -var_dump($r1->getUrl() == $r2->getUrl()); -$r1->send(); -var_dump($r1->getResponseInfo() == $r2->getResponseInfo()); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -bool(false) -bool(false) -bool(false) -Done diff --git a/tests/data.txt b/tests/data.txt deleted file mode 100644 index 2426113..0000000 --- a/tests/data.txt +++ /dev/null @@ -1,10 +0,0 @@ -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 diff --git a/tests/data/message_r_multipart_put.txt b/tests/data/message_r_multipart_put.txt new file mode 100644 index 0000000..52776d4 --- /dev/null +++ b/tests/data/message_r_multipart_put.txt @@ -0,0 +1,65 @@ +PUT /docs/ HTTP/1.1 +User-Agent: curl/7.24.0 (x86_64-unknown-linux-gnu) libcurl/7.24.0 OpenSSL/1.0.0g zlib/1.2.6 libssh2/1.3.0 +Host: drop +Accept: */* +Content-Length: 2284 +Expect: 100-continue +Content-Type: multipart/form-data; boundary=----------------------------6e182425881c + +------------------------------6e182425881c +Content-Disposition: form-data; name="LICENSE"; filename="LICENSE" +Content-Type: application/octet-stream + +Copyright (c) 2011-2012, Michael WallnertestMethod -- - -- - -- -- -foo -- -bar -. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +------------------------------6e182425881c +Content-Disposition: form-data; name="composer"; filename="composer.json" +Content-Type: application/octet-stream + +{ + "name": "mike_php_net/autocracy", + "type": "library", + "description": "http\\Controller preserves your autocracy", + "keywords": ["http", "controller", "pecl", "pecl_http"], + "homepage": "http://github.com/mike-php-net/autocracy", + "license": "BSD-2", + "authors": [ + { + "name": "Michael Wallner", + "email": "mike@php.net" + } + ], + "require": { + "php": ">=5.4.0", + "pecl/pecl_http": "2.*" + }, + "autoload": { + "psr-0": { + "http\\Controller": "lib" + } + } +} + +------------------------------6e182425881c-- diff --git a/tests/data/message_rr_empty.txt b/tests/data/message_rr_empty.txt new file mode 100644 index 0000000..3ecefde --- /dev/null +++ b/tests/data/message_rr_empty.txt @@ -0,0 +1,19 @@ +GET /default/empty.txt HTTP/1.1 +Host: localhost +Connection: close + +HTTP/1.1 200 OK +Date: Wed, 25 Aug 2010 12:11:44 GMT +Server: Apache/2.2.16 (Unix) + mod_ssl/2.2.16 + OpenSSL/1.0.0a + mod_fastcgi/2.4.6 +Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT +ETag: "2002a-0-48549d615a35c" +Accept-Ranges: bytes +Content-Length: 0 +Vary: Accept-Encoding +Connection: close +Content-Type: text/plain + + diff --git a/tests/data/message_rr_empty_chunked.txt b/tests/data/message_rr_empty_chunked.txt new file mode 100644 index 0000000..152c1a7 --- /dev/null +++ b/tests/data/message_rr_empty_chunked.txt @@ -0,0 +1,15 @@ +GET /default/empty.php HTTP/1.1 +Connection: close +Host: localhost + +HTTP/1.1 200 OK +Date: Thu, 26 Aug 2010 11:41:02 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +X-Powered-By: PHP/5.3.3 +Vary: Accept-Encoding +Connection: close +Transfer-Encoding: chunked +Content-Type: text/html + +0 + diff --git a/tests/data/message_rr_empty_gzip.txt b/tests/data/message_rr_empty_gzip.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ce1697e42a97bb4bfb3a23a124440ce3fd79236 GIT binary patch literal 443 zcmZvY-%i3X6vj!oF?|V7xYERJ-Pk77E20DvM=&z=($wy-H5pyA7Q%Q1U)qY ZfaEU)un8+IGG@T3F`!OAz`YSvJNps2joS%7tVm1ZwNem1qj7N(SXg zYVz19g~G~4F%WfQkdS@@M3ln%nLKfe4DxD!2T=;Med!7z1v+I(!srwhtDJ1GJz&dV zrn#svi2TS8Q@D9k@^}lorua0b?z3x+YO~3lN$OL6u5P)pqLi*9_EVC%pSN-@w-O5m zA6Pi$iQC=&DTkCLF&p2XmFGEkw~U ---FILE-- - ---EXPECTF-- -%aTEST -Thu, 01 Jan 1970 00:00:01 GMT -Fri, 13 Feb 2009 23:31:30 GMT - diff --git a/tests/date_002.phpt b/tests/date_002.phpt deleted file mode 100644 index aeb1205..0000000 --- a/tests/date_002.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -http_date() without timestamp ---SKIPIF-- - ---FILE-- - 1); -echo "$t\n$d\nDone\n"; -?> ---EXPECTF-- -%aTEST -bool(true) -%d -%a, %d %a %d %d:%d:%d GMT -Done diff --git a/tests/encoding_objects_001.phpt b/tests/encoding_objects_001.phpt deleted file mode 100644 index 60fe4cd..0000000 --- a/tests/encoding_objects_001.phpt +++ /dev/null @@ -1,35 +0,0 @@ ---TEST-- -encoding stream objects ---SKIPIF-- - ---FILE-- -flush($d->flush("Hi ")); -echo $i->finish($d->finish("there!\n")); -echo $i->finish($d->finish("Yo...\n")); - -$id = $i->update($d->update($pd = file_get_contents(__FILE__))); -foreach (glob('*.phpt') as $f) { - $id .= $i->update($d->update($tmp = file_get_contents($f))); - $pd .= $tmp; -} -$id .= $i->finish($d->finish()); - -var_dump($id == $pd); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -Hi there! -Yo... -bool(true) -Done - diff --git a/tests/encodings.phpt b/tests/encodings.phpt deleted file mode 100644 index e55c6b9..0000000 --- a/tests/encodings.phpt +++ /dev/null @@ -1,44 +0,0 @@ ---TEST-- -encodings ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -bool(true) -bool(true) -bool(true) -Done diff --git a/tests/envrequestbody001.phpt b/tests/envrequestbody001.phpt new file mode 100644 index 0000000..2351186 --- /dev/null +++ b/tests/envrequestbody001.phpt @@ -0,0 +1,15 @@ +--TEST-- +env request body +--SKIPIF-- + include "skipif.inc"; +--PUT-- +Content-Type: skip/me +foo +--FILE-- + +var_dump((string) \http\Env::getRequestBody()); +?> +DONE +--EXPECT-- +string(3) "foo" +DONE diff --git a/tests/envrequestbody002.phpt b/tests/envrequestbody002.phpt new file mode 100644 index 0000000..ec7d2d5 --- /dev/null +++ b/tests/envrequestbody002.phpt @@ -0,0 +1,20 @@ +--TEST-- +env request body +--SKIPIF-- + include "skipif.inc"; +--PUT-- +Content-Type: application/x-www-form-urlencoded +foo=bar&baz=buh +--FILE-- + +var_dump($_POST); +?> +DONE +--EXPECT-- +array(2) { + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(3) "buh" +} +DONE diff --git a/tests/envrequestbody003.phpt b/tests/envrequestbody003.phpt new file mode 100644 index 0000000..a22dbbd --- /dev/null +++ b/tests/envrequestbody003.phpt @@ -0,0 +1,48 @@ +--TEST-- +env request body +--SKIPIF-- + include "skipif.inc"; +--PUT-- +Content-Type: multipart/form-data;boundary=123 +--123 +Content-Disposition: form-data; name="foo" + +bar +--123 +Content-Disposition: form-data; name="baz" + +buh +--123 +Content-Disposition: form-data; name="up"; filename="up.txt" + +foo=bar&baz=buh +--123-- +--FILE-- + +var_dump($_POST); +var_dump($_FILES); +?> +DONE +--EXPECTF-- +array(2) { + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(3) "buh" +} +array(1) { + ["up"]=> + array(5) { + ["name"]=> + string(6) "up.txt" + ["type"]=> + string(0) "" + ["tmp_name"]=> + string(14) "%s" + ["error"]=> + int(0) + ["size"]=> + int(15) + } +} +DONE diff --git a/tests/envrequestfiles001.phpt b/tests/envrequestfiles001.phpt new file mode 100644 index 0000000..9a577c9 --- /dev/null +++ b/tests/envrequestfiles001.phpt @@ -0,0 +1,40 @@ +--TEST-- +env request grabbing $_FILES +--SKIPIF-- + +--POST_RAW-- +Content-Type: multipart/form-data;boundary=--123 + +----123 +Content-Disposition: form-data;filename="foo.bar" + +foo +bar + +----123 +Content-Disposition: form-data;filename="bar.foo" + +bar +foo + +----123-- +--FILE-- +getFiles(); + +foreach ($_FILES as $i => $file) { + foreach (array("name","type","size","error","file") as $key) { + if ($file[$key == "file" ? "tmp_name" : $key] != $f[$i][$key]) { + printf("%d.%s differs: '%s' != '%s'\n", $i, $key, $f[$i][$key], $file[$key]); + } + } +} + +?> +DONE +--EXPECT-- +TEST +DONE diff --git a/tests/envrequestfiles002.phpt b/tests/envrequestfiles002.phpt new file mode 100644 index 0000000..afc5144 --- /dev/null +++ b/tests/envrequestfiles002.phpt @@ -0,0 +1,47 @@ +--TEST-- +env request grabbing $_FILES from array +--SKIPIF-- + +--POST_RAW-- +Content-Type: multipart/form-data;boundary=--123 + +----123 +Content-Disposition: form-data;filename=file1;name=file[] + +first +----123 +Content-Disposition: form-data;filename=file2;name=file[] + +second +----123 +Content-Disposition: form-data;filename=file3;name=file[] + +third +----123-- +--FILE-- + $data) { + foreach ($data["tmp_name"] as $i => $file) { + $f[$name][$i] = array( + "file" => $file, + "name" => $data["name"][$i], + "size" => $data["size"][$i], + "type" => $data["type"][$i], + "error"=> $data["error"][$i] + ); + } +} + +var_dump($f == $r->getFiles()); + +?> +DONE +--EXPECT-- +TEST +bool(true) +DONE diff --git a/tests/envrequestform.phpt b/tests/envrequestform.phpt new file mode 100644 index 0000000..337bb54 --- /dev/null +++ b/tests/envrequestform.phpt @@ -0,0 +1,24 @@ +--TEST-- +env request form +--SKIPIF-- + +--POST-- +a=b&b=c&r[]=1&r[]=2 +--FILE-- +getForm()); +printf("%s\n", $r->getForm("b", "s", null, true)); +printf("%s\n", $r->getForm("x", "s", "nooo")); +printf("%s\n", $r->getForm()); +?> +DONE +--EXPECT-- +TEST +a=b&b=c&r%5B0%5D=1&r%5B1%5D=2 +c +nooo +a=b&r%5B0%5D=1&r%5B1%5D=2 +DONE diff --git a/tests/envrequestheader001.phpt b/tests/envrequestheader001.phpt new file mode 100644 index 0000000..b259ea5 --- /dev/null +++ b/tests/envrequestheader001.phpt @@ -0,0 +1,30 @@ +--TEST-- +env request header +--SKIPIF-- + include "skipif.inc"; +--POST-- +a=b +--ENV-- +HTTP_HOST=foo.bar +HTTP_ACCEPT=*/* +--FILE-- + + +var_dump(http\Env::getRequestHeader("nono")); +var_dump(http\Env::getRequestHeader("Host")); +var_dump(http\Env::getRequestHeader("content-type")); +var_dump(http\Env::getRequestHeader()); +--EXPECTF-- +NULL +string(%d) "foo.bar" +string(%d) "application/x-www-form-urlencoded" +array(4) { + ["Host"]=> + string(7) "foo.bar" + ["Accept"]=> + string(3) "*/*" + ["Content-Length"]=> + string(1) "3" + ["Content-Type"]=> + string(33) "application/x-www-form-urlencoded" +} diff --git a/tests/envrequestjson001.phpt b/tests/envrequestjson001.phpt new file mode 100644 index 0000000..3dfd9a8 --- /dev/null +++ b/tests/envrequestjson001.phpt @@ -0,0 +1,32 @@ +--TEST-- +env request json +--SKIPIF-- + +--POST_RAW-- +Content-Type: application/json + +{"foo": "bar", "a": [1,2,3]} +--FILE-- + +Done +--EXPECT-- +Test +Array +( + [foo] => bar + [a] => Array + ( + [0] => 1 + [1] => 2 + [2] => 3 + ) + +) +Done + diff --git a/tests/envrequestjson002.phpt b/tests/envrequestjson002.phpt new file mode 100644 index 0000000..4c404c0 --- /dev/null +++ b/tests/envrequestjson002.phpt @@ -0,0 +1,32 @@ +--TEST-- +env request json +--SKIPIF-- + +--PUT-- +Content-Type: application/json + +{"foo": "bar", "a": [1,2,3]} +--FILE-- + +Done +--EXPECT-- +Test +Array +( + [foo] => bar + [a] => Array + ( + [0] => 1 + [1] => 2 + [2] => 3 + ) + +) +Done + diff --git a/tests/envrequestquery.phpt b/tests/envrequestquery.phpt new file mode 100644 index 0000000..2e21ab9 --- /dev/null +++ b/tests/envrequestquery.phpt @@ -0,0 +1,24 @@ +--TEST-- +env request query +--SKIPIF-- + +--GET-- +a=b&b=c&r[]=1&r[]=2 +--FILE-- +getQuery()); +printf("%s\n", $r->getQuery("b", "s", null, true)); +printf("%s\n", $r->getQuery("x", "s", "nooo")); +printf("%s\n", $r->getQuery()); +?> +DONE +--EXPECT-- +TEST +a=b&b=c&r%5B0%5D=1&r%5B1%5D=2 +c +nooo +a=b&r%5B0%5D=1&r%5B1%5D=2 +DONE diff --git a/tests/envresponse001.phpt b/tests/envresponse001.phpt new file mode 100644 index 0000000..9d55a5b --- /dev/null +++ b/tests/envresponse001.phpt @@ -0,0 +1,23 @@ +--TEST-- +env response message +--SKIPIF-- + +--POST-- +a=b +--ENV-- +HTTP_ACCEPT_ENCODING=gzip +--FILE-- +setHeader("foo","bar"); +$r->setContentEncoding(http\env\Response::CONTENT_ENCODING_GZIP); +$r->setBody(new http\message\Body(fopen(__FILE__,"r"))); +$r->send(); + +--EXPECTHEADERS-- +Foo: bar +Content-Encoding: gzip +Vary: Accept-Encoding +--EXPECTREGEX-- +^\x1f\x8b\x08.+ diff --git a/tests/envresponse002.phpt b/tests/envresponse002.phpt new file mode 100644 index 0000000..e11f7bb --- /dev/null +++ b/tests/envresponse002.phpt @@ -0,0 +1,28 @@ +--TEST-- +env response cache negative +--SKIPIF-- + +--GET-- +a=b +--ENV-- +HTTP_IF_MODIFIED_SINCE=Fri, 13 Feb 2009 23:31:30 GMT +HTTP_IF_NONE_MATCH=0000-00-0000 +--FILE-- +setBody(new http\Message\Body(fopen(__FILE__,"rb"))); +$r->setEtag("abc"); +$r->setLastModified(1234567891); +$r->send(); +?> +--EXPECTHEADERS-- +ETag: "abc" +Last-Modified: Fri, 13 Feb 2009 23:31:31 GMT +--EXPECT-- +setBody(new http\Message\Body(fopen(__FILE__,"rb"))); +$r->setEtag("abc"); +$r->setLastModified(1234567891); +$r->send(); +?> diff --git a/tests/envresponse003.phpt b/tests/envresponse003.phpt new file mode 100644 index 0000000..3bbf760 --- /dev/null +++ b/tests/envresponse003.phpt @@ -0,0 +1,24 @@ +--TEST-- +env response ranges +--SKIPIF-- + +--ENV-- +HTTP_RANGE=bytes=2-4 +--GET-- +a=b +--FILE-- +setContentType("text/plain"); +$r->setContentDisposition( + array("attachment" => array(array("filename" => basename(__FILE__)))) +); +$r->setBody(new http\Message\Body(fopen(__FILE__, "rb"))); +$r->send(); + +?> +--EXPECTHEADERS-- +Content-Type: text/plain +--EXPECTF-- +php diff --git a/tests/envresponse004.phpt b/tests/envresponse004.phpt new file mode 100644 index 0000000..f84c860 --- /dev/null +++ b/tests/envresponse004.phpt @@ -0,0 +1,28 @@ +--TEST-- +env reponse callback +--SKIPIF-- + +--GET-- +dummy=1 +--FILE-- +setCacheControl("public,must-revalidate,max-age=0"); +$r->setThrottleRate(1, 0.1); +ob_start($r); + +echo "foo"; +echo "bar"; + +ob_end_flush(); +$r->send(); +--EXPECTHEADERS-- +Accept-Ranges: bytes +Cache-Control: public,must-revalidate,max-age=0 +ETag: "9ef61f95" +--EXPECTF-- +foobar diff --git a/tests/envresponse005.phpt b/tests/envresponse005.phpt new file mode 100644 index 0000000..6d55168 --- /dev/null +++ b/tests/envresponse005.phpt @@ -0,0 +1,23 @@ +--TEST-- +env response cache positive +--SKIPIF-- + +--GET-- +a=b +--ENV-- +HTTP_IF_MODIFIED_SINCE=Fri, 13 Feb 2009 23:31:32 GMT +--FILE-- +setBody(new http\Message\Body(fopen(__FILE__,"rb"))); +$r->setEtag("abc"); +$r->setLastModified(1234567891); +$r->isCachedByEtag("If-None-Match") and die("Huh? etag? really?\n"); +$r->isCachedByLastModified("If-Modified-Since") or die("yep, I should be cached"); +$r->send(); +?> +--EXPECTHEADERS-- +HTTP/1.1 304 Not Modified +ETag: "abc" +Last-Modified: Fri, 13 Feb 2009 23:31:31 GMT +--EXPECT-- diff --git a/tests/envresponse006.phpt b/tests/envresponse006.phpt new file mode 100644 index 0000000..76141c1 --- /dev/null +++ b/tests/envresponse006.phpt @@ -0,0 +1,31 @@ +--TEST-- +env response stream +--SKIPIF-- + +--FILE-- +addHeader("foo", array("bar","baz")); +$r->getBody()->append("foo"); + +$r->send($f); + +rewind($f); +var_dump(stream_get_contents($f)); +?> +Done +--EXPECT-- +Test +string(77) "HTTP/1.1 200 OK +Accept-Ranges: bytes +Foo: bar, baz +ETag: "8c736521" + +foo" +Done diff --git a/tests/envresponse007.phpt b/tests/envresponse007.phpt new file mode 100644 index 0000000..5495fe2 --- /dev/null +++ b/tests/envresponse007.phpt @@ -0,0 +1,39 @@ +--TEST-- +env response env request +--SKIPIF-- + +--GET-- +dummy=1 +--FILE-- +setHeader("Range", "bytes=2-4"); + +$res = new http\Env\Response; +$res->setEnvRequest($req); +$res->setContentType("text/plain"); +$res->getBody()->append("012345679"); +$res->send($tmp); + +rewind($tmp); +var_dump(stream_get_contents($tmp)); + +?> +Done +--EXPECTF-- +Test +string(%d) "HTTP/1.1 206 Partial Content%c +Accept-Ranges: bytes%c +X-Powered-By: %s%c +Content-Type: text/plain%c +Content-Range: bytes 2-4/9%c +%c +234" +Done diff --git a/tests/envresponse008.phpt b/tests/envresponse008.phpt new file mode 100644 index 0000000..379ab57 --- /dev/null +++ b/tests/envresponse008.phpt @@ -0,0 +1,30 @@ +--TEST-- +env response stream message +--SKIPIF-- + +--ENV-- +HTTP_ACCEPT_ENCODING=gzip +--FILE-- +setHeader("foo","bar"); +$r->setContentEncoding(http\env\Response::CONTENT_ENCODING_GZIP); +$r->setBody(new http\message\Body(fopen(__FILE__,"r"))); +$r->send($f); + +rewind($f); +var_dump(stream_get_contents($f)); + +--EXPECTREGEX-- +string\(\d+\) "HTTP\/1\.1 200 OK +Accept-Ranges: bytes +Foo: bar +Content-Encoding: gzip +Vary: Accept-Encoding +ETag: "\w+-\w+-\w+" +Last-Modified: \w+, \d+ \w+ \d{4} \d\d:\d\d:\d\d GMT + +\x1f\x8b\x08.+ diff --git a/tests/envresponse009.phpt b/tests/envresponse009.phpt new file mode 100644 index 0000000..2a337e4 --- /dev/null +++ b/tests/envresponse009.phpt @@ -0,0 +1,39 @@ +--TEST-- +env response stream cache negative +--SKIPIF-- + +--GET-- +a=b +--ENV-- +HTTP_IF_MODIFIED_SINCE=Fri, 13 Feb 2009 23:31:30 GMT +HTTP_IF_NONE_MATCH=0000-00-0000 +--FILE-- +setBody(new http\Message\Body(fopen(__FILE__,"rb"))); +$r->setEtag("abc"); +$r->setLastModified(1234567891); +$r->send($f); +rewind($f); +var_dump(stream_get_contents($f)); +?> +--EXPECTF-- +string(%d) "HTTP/1.1 200 OK%c +Accept-Ranges: bytes%c +X-Powered-By: %s%c +ETag: "abc"%c +Last-Modified: %s%c +%c +setBody(new http\Message\Body(fopen(__FILE__,"rb"))); +$r->setEtag("abc"); +$r->setLastModified(1234567891); +$r->send($f); +rewind($f); +var_dump(stream_get_contents($f)); +?> +" + diff --git a/tests/envresponse010.phpt b/tests/envresponse010.phpt new file mode 100644 index 0000000..d365497 --- /dev/null +++ b/tests/envresponse010.phpt @@ -0,0 +1,29 @@ +--TEST-- +env response stream ranges +--SKIPIF-- + +--ENV-- +HTTP_RANGE=bytes=2-4 +--GET-- +a=b +--FILE-- +setContentType("text/plain"); +$r->setContentDisposition( + array("attachment" => array(array("filename" => basename(__FILE__)))) +); +$r->setBody(new http\Message\Body(fopen(__FILE__, "rb"))); +$r->send($f); +rewind($f); +var_dump(stream_get_contents($f)); +?> +--EXPECTF-- +string(%i) "HTTP/1.1 206 Partial Content%c +Accept-Ranges: bytes%c +X-Powered-By: PHP/%s%c +Content-Type: text/plain%c +Content-Range: bytes 2-4/311%c +%c +php" diff --git a/tests/envresponse011.phpt b/tests/envresponse011.phpt new file mode 100644 index 0000000..45e2f6e --- /dev/null +++ b/tests/envresponse011.phpt @@ -0,0 +1,24 @@ +--TEST-- +env response cache positive with env message +--SKIPIF-- + +--GET-- +dummy=1 +--FILE-- +setHeader("If-Modified-Since", "Fri, 13 Feb 2009 23:31:32 GMT"); +$r = new http\Env\Response; +$r->setEnvRequest($e); +$r->setBody(new http\Message\Body(fopen(__FILE__,"rb"))); +$r->setEtag("abc"); +$r->setLastModified(1234567891); +$r->isCachedByEtag("If-None-Match") and die("Huh? etag? really?\n"); +$r->isCachedByLastModified("If-Modified-Since") or die("yep, I should be cached"); +$r->send(); +?> +--EXPECTHEADERS-- +HTTP/1.1 304 Not Modified +ETag: "abc" +Last-Modified: Fri, 13 Feb 2009 23:31:31 GMT +--EXPECT-- diff --git a/tests/envresponse012.phpt b/tests/envresponse012.phpt new file mode 100644 index 0000000..58e0a3b --- /dev/null +++ b/tests/envresponse012.phpt @@ -0,0 +1,29 @@ +--TEST-- +env response content disposition +--SKIPIF-- + +--GET-- +dummy=1 +--FILE-- +setContentDisposition(array("attachment"=>array("filename"=>basename(__FILE__)))); +$r->setBody(new http\Message\Body(fopen(__FILE__,"r"))); +$r->send(); + +?> +--EXPECTHEADERS-- +Content-Disposition: attachment;filename=envresponse012.php +--EXPECT-- +setContentDisposition(array("attachment"=>array("filename"=>basename(__FILE__)))); +$r->setBody(new http\Message\Body(fopen(__FILE__,"r"))); +$r->send(); + +?> + diff --git a/tests/envresponse013.phpt b/tests/envresponse013.phpt new file mode 100644 index 0000000..d21f604 --- /dev/null +++ b/tests/envresponse013.phpt @@ -0,0 +1,29 @@ +--TEST-- +env response deflate +--SKIPIF-- + +--GET-- +dummy=1 +--FILE-- +setHeader("Accept-Encoding", "deflate"); + +$res = new http\Env\Response; +$res->setCacheControl("public, max-age=3600"); +$res->setContentEncoding(http\Env\Response::CONTENT_ENCODING_GZIP); +$res->getBody()->append("foobar"); + +$res->setEnvRequest($req); +$res->send(); +?> +--EXPECTHEADERS-- +Content-Encoding: deflate +Vary: Accept-Encoding +Cache-Control: public, max-age=3600 +--EXPECTREGEX-- +^\x78\x9c.+ + diff --git a/tests/envresponse014.phpt b/tests/envresponse014.phpt new file mode 100644 index 0000000..ef85e2c --- /dev/null +++ b/tests/envresponse014.phpt @@ -0,0 +1,24 @@ +--TEST-- +env response invalid ranges +--SKIPIF-- + +--FILE-- +setHeader("Range", "bytes=321-123,123-0"); +$res = new http\Env\Response; +$res->getBody()->append("foobar"); +$res->setEnvRequest($req); +$res->send($f); +rewind($f); +var_dump(stream_get_contents($f)); +--EXPECTF-- +string(96) "HTTP/1.1 416 Requested Range Not Satisfiable +Accept-Ranges: bytes +Content-Range: bytes */6 + +" + diff --git a/tests/envresponsebody001.phpt b/tests/envresponsebody001.phpt new file mode 100644 index 0000000..616760e --- /dev/null +++ b/tests/envresponsebody001.phpt @@ -0,0 +1,20 @@ +--TEST-- +env response body +--SKIPIF-- + +--INI-- +output_buffering=1 +--FILE-- +getBody()); +?> +Done +--EXPECTF-- +Test +string(5) "Test +" +Done diff --git a/tests/envresponsebody002.phpt b/tests/envresponsebody002.phpt new file mode 100644 index 0000000..1421b09 --- /dev/null +++ b/tests/envresponsebody002.phpt @@ -0,0 +1,24 @@ +--TEST-- +env response body error +--SKIPIF-- + +--INI-- +output_buffering=1 +--FILE-- +getBody()); +} catch (http\Exception $e) { + echo $e->getMessage(),"\n"; +} +?> +Done +--EXPECTF-- +Test +http\Env\Response::__construct(): Could not fetch response body, output has already been sent at %senvresponsebody002.php:3 +Done diff --git a/tests/envresponsecodes.phpt b/tests/envresponsecodes.phpt new file mode 100644 index 0000000..ec6ea21 --- /dev/null +++ b/tests/envresponsecodes.phpt @@ -0,0 +1,26 @@ +--TEST-- +env response codes +--SKIPIF-- + +--FILE-- + +Done +--EXPECT-- +Test +array(0) { +} +Done diff --git a/tests/envresponseheader001.phpt b/tests/envresponseheader001.phpt new file mode 100644 index 0000000..194f7d7 --- /dev/null +++ b/tests/envresponseheader001.phpt @@ -0,0 +1,39 @@ +--TEST-- +env response header +--SKIPIF-- + +--FILE-- + %s + [Foo] => bar + [More] => Array + ( + [0] => than + [1] => what's + [2] => good + ) + + [Content-Type] => text/html +) +Created diff --git a/tests/envresponseranges001.phpt b/tests/envresponseranges001.phpt new file mode 100644 index 0000000..8511fff --- /dev/null +++ b/tests/envresponseranges001.phpt @@ -0,0 +1,47 @@ +--TEST-- +ranges +--SKIPIF-- + include "skipif.php"; +--GET-- +a=b +--ENV-- +HTTP_RANGE=bytes=-3,000-001,1-1,0-0,100- +--FILE-- +setBody(new http\Message\Body(fopen(__FILE__, "rb"))); +$r->send(); + +?> +--EXPECTF-- +--%s%c +Content-Type: application/octet-stream%c +Content-Range: bytes 107-109/110%c +%c +?> +%c +--%s%c +Content-Type: application/octet-stream%c +Content-Range: bytes 0-1/110%c +%c +%c +--%s%c +Content-Type: application/octet-stream%c +Content-Range: bytes 1-1/110%c +%c +?%c +--%s%c +Content-Type: application/octet-stream%c +Content-Range: bytes 0-0/110%c +%c +<%c +--%s%c +Content-Type: application/octet-stream%c +Content-Range: bytes 100-109/110%c +%c +nd(); + +?> +%c +--%s-- \ No newline at end of file diff --git a/tests/etag001.phpt b/tests/etag001.phpt new file mode 100644 index 0000000..b3a2a53 --- /dev/null +++ b/tests/etag001.phpt @@ -0,0 +1,67 @@ +--TEST-- +etags with hash +--SKIPIF-- +=") or die("skip PHP>=5.4 required"); +?> +--FILE-- +append("Hello, my old fellow."); +foreach (hash_algos() as $algo) { + if ($algo == "gost-crypto") continue; + ini_set("http.etag.mode", $algo); + printf("%10s: %s\n", + $algo, + $body->etag() + ); +} +?> +DONE +--EXPECT-- + md2: 9bf7d8506d7453a85dc34fa730cbc16a + md4: 137008b9144843f5bfcc6651688acc41 + md5: 6ce3cc8f3861fb7fd0d77739f11cd29c + sha1: ad84012eabe27a61762a97138d9d2623f4f1a7a9 + sha224: 91be9bd30cec7fb7fb0279e40211fa71f8a7ab933f9f1a832d7c60cb + sha256: ed9ecfe5c76d51179c3c1065916fdb8d94aee05577f187bd763cdc962bba1f42 + sha384: 923a756152da113db192958da485c7881e7c4811d2d34e22f4d74cd45310d983f7fb1c5527a5f9037a4c7b649a6cc2b2 + sha512: ad5ea693b8df4457d08d835ad5ccf7b626b66285f8424b3ec59e54c63bf63feef9a92baaba71c38d7bd9a1135488499fc835a8818390965c9ce8a5e4c40e519f + ripemd128: b9e8d5864b5821d72e66101a9a0e730a + ripemd160: d697a33676aece781b72f6fcb95f4c730367706b + ripemd256: 9c3a73ab03e6d7d3471cf70316c4ff3ec56212d25730d382fb1480346529742b + ripemd320: 5a6ee6b7c35c64d9c91019b9a1ceb2ab2ae19915f3dc96b0f244e15581d750a775a3682c5e70ee23 + whirlpool: 2cb738084edaede8b36e9c8d81f5d30d9afe12bf60715073a6651c32c3448a6eeeff9f9715a8c996291ab3cd6c9a9caac8bea3b0eeb1c88afe6ad46fdd0cef83 +tiger128,3: f3055bdb40b06abac716a27a654b295d +tiger160,3: f3055bdb40b06abac716a27a654b295dc07e1ab9 +tiger192,3: f3055bdb40b06abac716a27a654b295dc07e1ab915b56529 +tiger128,4: e6a1628a4da8fa6adf4ca866c5e235b5 +tiger160,4: e6a1628a4da8fa6adf4ca866c5e235b51939bb61 +tiger192,4: e6a1628a4da8fa6adf4ca866c5e235b51939bb61ecf8423f + snefru: 8f50c66c8f0a1510f9c591a2b7a070853d4770c60a38394c8857918dd91a2e5b + snefru256: 8f50c66c8f0a1510f9c591a2b7a070853d4770c60a38394c8857918dd91a2e5b + gost: efc79cdd01331adf80b30af816ff7a934f3f3df3085294a310918cacff3500f0 + adler32: 4ff5075d + crc32: 757b06f7 + crc32b: e56655c5 + fnv132: ebd1fa1f + fnv164: 9790ce01eba3ae9f + joaat: 70a407c9 +haval128,3: 68a1bee33d2a4fa5543be7fa871f84ea +haval160,3: b4204e8c4f3c993385d997539afa723888700bbd +haval192,3: 6c7f3442f5b5c7d338bd31ab9de1216576ce6633f8de9e03 +haval224,3: 4edf7debeea48b94af73f47c1a4449dff516b69ba36f6659ed59689c +haval256,3: eb919a27c9e598cf3559e79fca10119d54b6f704b779cd665ab5352eb17726c4 +haval128,4: 184195034f2e5b2a0d04dcc42fac3275 +haval160,4: b13d521378d7b74b226430355fa6f4ceba0782c2 +haval192,4: 4e53f767e7dbff4abb8ebf767d672db3df77de7d9de6e9d9 +haval224,4: 1208cc9fc1c23de3985f5a5214ebb67c846cecd32f96d950ef3ef770 +haval256,4: 658d40b21f87ebe45cf6ec822402d1ca6965f263358e3927a92beba837785735 +haval128,5: 938933eefe94e217d73a27909f89f8c6 +haval160,5: 07b9e4a6c451acb5930081f414a06d948c1b70ba +haval192,5: 997ca1515369b0051e9fcc736c1096618ef936f185a19ebe +haval224,5: b46f2aada87d9e7a38b126268dce9779303aa4999d42f5c74427e362 +haval256,5: 4e0b601e5ee93d6c2a449793e756e9ca6e03fb618c9f2ed849a7f8ca29ef9112 +DONE diff --git a/tests/etag_mode_031.phpt b/tests/etag_mode_031.phpt deleted file mode 100644 index 5f72338..0000000 --- a/tests/etag_mode_031.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -crc32 etag (may fail because PHPs crc32 is actually crc32b) ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: private, must-revalidate, max-age=0 -Accept-Ranges: bytes -ETag: "4e818847" -Content-Length: 4 -Content-type: %a - -abc diff --git a/tests/etag_mode_032.phpt b/tests/etag_mode_032.phpt deleted file mode 100644 index cfb5c35..0000000 --- a/tests/etag_mode_032.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -sha1 etag ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: private, must-revalidate, max-age=0 -Accept-Ranges: bytes -ETag: "03cfd743661f07975fa2f1220c5194cbaff48451" -Content-Length: 4 -Content-type: %a - -abc diff --git a/tests/etag_mode_033.phpt b/tests/etag_mode_033.phpt deleted file mode 100644 index c39cc65..0000000 --- a/tests/etag_mode_033.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -md5 etag ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: private, must-revalidate, max-age=0 -Accept-Ranges: bytes -ETag: "0bee89b07a248e27c83fc3d5951213c1" -Content-Length: 4 -Content-type: %a - -abc diff --git a/tests/etag_mode_034.phpt b/tests/etag_mode_034.phpt deleted file mode 100644 index f97bda9..0000000 --- a/tests/etag_mode_034.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -ext/hash etag ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: private, must-revalidate, max-age=0 -Accept-Ranges: bytes -ETag: "edeaaff3f1774ad2888673770c6d64097e391bc362d7d6fb34982ddf0efd18cb" -Content-Length: 4 -Content-type: %a - -abc diff --git a/tests/etag_mode_041.phpt b/tests/etag_mode_041.phpt deleted file mode 100644 index 0834ede..0000000 --- a/tests/etag_mode_041.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -ob crc32 etag (may fail because PHPs crc32 is actually crc32b) ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: private, must-revalidate, max-age=0 -ETag: "4e818847" -Content-type: %a - -abc diff --git a/tests/etag_mode_042.phpt b/tests/etag_mode_042.phpt deleted file mode 100644 index 1d74254..0000000 --- a/tests/etag_mode_042.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -ob sha1 etag ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: private, must-revalidate, max-age=0 -ETag: "03cfd743661f07975fa2f1220c5194cbaff48451" -Content-type: %a - -abc diff --git a/tests/etag_mode_043.phpt b/tests/etag_mode_043.phpt deleted file mode 100644 index 98777e1..0000000 --- a/tests/etag_mode_043.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -ob md5 etag ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: private, must-revalidate, max-age=0 -ETag: "0bee89b07a248e27c83fc3d5951213c1" -Content-type: %a - -abc diff --git a/tests/etag_mode_044.phpt b/tests/etag_mode_044.phpt deleted file mode 100644 index 6992860..0000000 --- a/tests/etag_mode_044.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -ob ext/hash etag ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%a -Cache-Control: private, must-revalidate, max-age=0 -ETag: "edeaaff3f1774ad2888673770c6d64097e391bc362d7d6fb34982ddf0efd18cb" -Content-type: %a - -abc diff --git a/tests/exceptions.phpt b/tests/exceptions.phpt deleted file mode 100644 index fdda3f3..0000000 --- a/tests/exceptions.phpt +++ /dev/null @@ -1,53 +0,0 @@ ---TEST-- -exceptions ---SKIPIF-- - ---FILE-- - 'Runtime', - HTTP_E_INVALID_PARAM => 'InvalidParam', - HTTP_E_HEADER => 'Header', - HTTP_E_MALFORMED_HEADERS => 'MalformedHeaders', - HTTP_E_REQUEST_METHOD => 'RequestMethod', - HTTP_E_MESSAGE_TYPE => 'MessageType', - HTTP_E_ENCODING => 'Encoding', - HTTP_E_REQUEST => 'Request', - HTTP_E_REQUEST_POOL => 'RequestPool', - HTTP_E_SOCKET => 'Socket', - HTTP_E_RESPONSE => 'Response', - HTTP_E_URL => 'Url', -); - -foreach ($e as $i => $c) { - try { - $n = "Http{$c}Exception"; - throw new $n; - } catch (HttpException $x) { - printf("%2d: %s\n", $i, get_class($x)); - } -} -echo "Done\n"; -?> ---EXPECTF-- -%aTEST - 1: HttpRuntimeException - 2: HttpInvalidParamException - 3: HttpHeaderException - 4: HttpMalformedHeadersException - 5: HttpRequestMethodException - 6: HttpMessageTypeException - 7: HttpEncodingException - 8: HttpRequestException - 9: HttpRequestPoolException -10: HttpSocketException -11: HttpResponseException -12: HttpUrlException -Done diff --git a/tests/filterchunked.phpt b/tests/filterchunked.phpt new file mode 100644 index 0000000..f2d2850 --- /dev/null +++ b/tests/filterchunked.phpt @@ -0,0 +1,29 @@ +--TEST-- +chunked filter +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/tests/filterzlib.phpt b/tests/filterzlib.phpt new file mode 100644 index 0000000..bbfac86 --- /dev/null +++ b/tests/filterzlib.phpt @@ -0,0 +1,29 @@ +--TEST-- +zlib filter +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/tests/get_request_data_001.phpt b/tests/get_request_data_001.phpt deleted file mode 100644 index ea79b26..0000000 --- a/tests/get_request_data_001.phpt +++ /dev/null @@ -1,40 +0,0 @@ ---TEST-- -get request data ---SKIPIF-- - ---POST-- -a=b&c=d ---FILE-- - ---EXPECTF-- -%aTEST -Array -( - [Accept-Charset] => iso-8859-1, * - [Accept-Encoding] => none - [Host] => localhost - [User-Agent] => Mozilla/5.0 -) -string(7) "a=b&c=d" -string(7) "a=b&c=d" -string(7) "a=b&c=d" -string(7) "a=b&c=d" -Done diff --git a/tests/header001.phpt b/tests/header001.phpt new file mode 100644 index 0000000..5e3d938 --- /dev/null +++ b/tests/header001.phpt @@ -0,0 +1,20 @@ +--TEST-- +header string +--SKIPIF-- + +--FILE-- + +Done +--EXPECT-- +Test +bool(true) +Done diff --git a/tests/header002.phpt b/tests/header002.phpt new file mode 100644 index 0000000..36b25c7 --- /dev/null +++ b/tests/header002.phpt @@ -0,0 +1,20 @@ +--TEST-- +header numeric +--SKIPIF-- + +--FILE-- + +Done +--EXPECT-- +Test +bool(true) +Done diff --git a/tests/header003.phpt b/tests/header003.phpt new file mode 100644 index 0000000..d02e7e7 --- /dev/null +++ b/tests/header003.phpt @@ -0,0 +1,23 @@ +--TEST-- +header serialize +--SKIPIF-- + +--FILE-- + +Done +--EXPECT-- +Test +bool(true) +bool(true) +Done diff --git a/tests/header004.phpt b/tests/header004.phpt new file mode 100644 index 0000000..1517f1f --- /dev/null +++ b/tests/header004.phpt @@ -0,0 +1,34 @@ +--TEST-- +header match +--SKIPIF-- + +--FILE-- +match("gzip", http\Header::MATCH_WORD)); +var_dump($ae->match("gzip", http\Header::MATCH_WORD|http\Header::MATCH_CASE)); +var_dump($ae->match("gzip", http\Header::MATCH_STRICT)); +var_dump($ae->match("deflate", http\Header::MATCH_WORD)); +var_dump($ae->match("deflate", http\Header::MATCH_WORD|http\Header::MATCH_CASE)); +var_dump($ae->match("deflate", http\Header::MATCH_STRICT)); +var_dump($ae->match("zip", http\Header::MATCH_WORD)); +var_dump($ae->match("gzip", http\Header::MATCH_FULL)); + +?> +Done +--EXPECT-- +Test +bool(true) +bool(true) +bool(false) +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +Done diff --git a/tests/header005.phpt b/tests/header005.phpt new file mode 100644 index 0000000..07c27cb --- /dev/null +++ b/tests/header005.phpt @@ -0,0 +1,32 @@ +--TEST-- +header negotiation +--SKIPIF-- + +--FILE-- +negotiate(array("text/plain","text/html"))); +var_dump("text/html" === $a->negotiate(array("text/plain","text/html"), $rs)); +var_dump(array("text/html"=>0.99, "text/plain"=>0.5) === $rs); +var_dump("text/plain" === $a->negotiate(array("foo/bar", "text/plain"), $rs)); +var_dump(array("text/plain"=>0.5) === $rs); +var_dump("foo/bar" === $a->negotiate(array("foo/bar"), $rs)); +var_dump(array() === $rs); + +?> +Done +--EXPECT-- +Test +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +Done diff --git a/tests/header006.phpt b/tests/header006.phpt new file mode 100644 index 0000000..92a6215 --- /dev/null +++ b/tests/header006.phpt @@ -0,0 +1,27 @@ +--TEST-- +header parsing +--SKIPIF-- + +--FILE-- +"bar","Bar"=>"foo") === http\Header::parse($header)); + +$headers = http\Header::parse($header, "http\\Header"); +var_dump(2 === count($headers)); +var_dump(2 === array_reduce($headers, function($count, $header) { + return $count + ($header instanceof http\Header); +}, 0)); +?> +Done +--EXPECT-- +Test +bool(true) +bool(true) +bool(true) +Done diff --git a/tests/header007.phpt b/tests/header007.phpt new file mode 100644 index 0000000..aa91901 --- /dev/null +++ b/tests/header007.phpt @@ -0,0 +1,21 @@ +--TEST-- +header parse error +--SKIPIF-- + +--FILE-- + +Done +--EXPECTF-- +Test + +Warning: http\Header::parse(): Could not parse headers in %s on line %d +Done diff --git a/tests/header008.phpt b/tests/header008.phpt new file mode 100644 index 0000000..089e2ea --- /dev/null +++ b/tests/header008.phpt @@ -0,0 +1,26 @@ +--TEST-- +header params +--SKIPIF-- + +--FILE-- + array("value" => true, "arguments" => array()), + "must-revalidate" => array("value" => true, "arguments" => array()), + "max-age" => array("value" => "0", "arguments" => array()), + ) === $header->getParams()->params +); + +?> +Done +--EXPECT-- +Test +bool(true) +Done diff --git a/tests/header009.phpt b/tests/header009.phpt new file mode 100644 index 0000000..d3ca1de --- /dev/null +++ b/tests/header009.phpt @@ -0,0 +1,25 @@ +--TEST-- +header params w/ args +--SKIPIF-- + +--FILE-- + array("value" => "bar", "arguments" => array()), + "bar" => array("value" => "bis", "arguments" => array("bis" => "where")) + ) === $header->getParams(".", "where", "is")->params +); + +?> +Done +--EXPECT-- +Test +bool(true) +Done diff --git a/tests/info.phpt b/tests/info.phpt new file mode 100644 index 0000000..373cb45 --- /dev/null +++ b/tests/info.phpt @@ -0,0 +1,19 @@ +--TEST-- +phpinfo +--SKIPIF-- + +--FILE-- + +Done +--EXPECTF-- +Test +%a +HTTP Support => enabled +Extension Version => 2.%s +%a +Done diff --git a/tests/info_001.phpt b/tests/info_001.phpt new file mode 100644 index 0000000..11b83f6 --- /dev/null +++ b/tests/info_001.phpt @@ -0,0 +1,61 @@ +--TEST-- +invalid HTTP info +--SKIPIF-- + +--FILE-- + +DONE +--EXPECTF-- +exception 'http\Exception\BadMessageException' with message 'Could not parse message: GET HTTP/1.1' in %s +Stack trace: +#0 %s: http\Message->__construct('GET HTTP/1.1') +#1 {main} +exception 'http\Exception\BadMessageException' with message 'Could not parse message: GET HTTP/1.123' in %s +Stack trace: +#0 %s: http\Message->__construct('GET HTTP/1.123') +#1 {main} +exception 'http\Exception\BadMessageException' with message 'Could not parse message: GETHTTP/1.1' in %s +Stack trace: +#0 %s: http\Message->__construct('GETHTTP/1.1') +#1 {main} +object(http\Message)#%d (9) { + ["type":protected]=> + int(1) + ["body":protected]=> + object(http\Message\Body)#%d (0) { + } + ["requestMethod":protected]=> + string(3) "GET" + ["requestUrl":protected]=> + string(1) "/" + ["responseStatus":protected]=> + string(0) "" + ["responseCode":protected]=> + int(0) + ["httpVersion":protected]=> + string(3) "1.1" + ["headers":protected]=> + array(0) { + } + ["parentMessage":protected]=> + NULL +} +DONE diff --git a/tests/log.inc b/tests/log.inc deleted file mode 100644 index f5e33b8..0000000 --- a/tests/log.inc +++ /dev/null @@ -1,23 +0,0 @@ - diff --git a/tests/match_request_header_001.phpt b/tests/match_request_header_001.phpt deleted file mode 100644 index 34aa3c2..0000000 --- a/tests/match_request_header_001.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -http_match_request_header() ---SKIPIF-- - ---ENV-- -HTTP_FOO=bar ---FILE-- - ---EXPECTF-- -%aTEST -bool(true) -bool(true) -bool(false) -Done diff --git a/tests/message001.phpt b/tests/message001.phpt new file mode 100644 index 0000000..230fd6b --- /dev/null +++ b/tests/message001.phpt @@ -0,0 +1,471 @@ +--TEST-- +message +--SKIPIF-- + +--FILE-- +getHttpVersion(), + $m->getType()==HttpMessage::TYPE_NONE, + $m->getHeaders() +); + +$m = new HttpMessage("GET / HTTP/1.1\r\n"); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_REQUEST, + $m->getRequestMethod(), + $m->getRequestUrl(), + $m->getHeaders() +); + +$m = new HttpMessage("HTTP/1.1 200 Okidoki\r\n"); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); + +echo "---\n"; + +$m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty.txt")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +$m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty_gzip.txt")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +$m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty_chunked.txt")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +$m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_helloworld_chunked.txt")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +echo "---\n"; + +$m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty.txt", "r+b")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +$m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty_gzip.txt", "r+b")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +$m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty_chunked.txt", "r+b")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +$m = new HttpMessage(fopen(__DIR__."/data/message_rr_helloworld_chunked.txt", "r+b")); +echo $m; +var_dump( + $m->getHttpVersion(), + $m->getType()==HttpMessage::TYPE_RESPONSE, + $m->getResponseCode(), + $m->getResponseStatus(), + $m->getHeaders() +); +echo $m->getParentMessage(); + +echo "Done\n"; +--EXPECTF-- +Test +string(3) "1.1" +bool(true) +array(0) { +} +GET / HTTP/1.1 +string(3) "1.1" +bool(true) +string(3) "GET" +string(1) "/" +array(0) { +} +HTTP/1.1 200 Okidoki +string(3) "1.1" +bool(true) +int(200) +string(7) "Okidoki" +array(0) { +} +--- +HTTP/1.1 200 OK +Date: Wed, 25 Aug 2010 12:11:44 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT +Etag: "2002a-0-48549d615a35c" +Accept-Ranges: bytes +Content-Length: 0 +Vary: Accept-Encoding +Connection: close +Content-Type: text/plain +X-Original-Content-Length: 0 +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(10) { + ["Date"]=> + string(29) "Wed, 25 Aug 2010 12:11:44 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["Last-Modified"]=> + string(29) "Wed, 28 Apr 2010 10:54:37 GMT" + ["Etag"]=> + string(23) ""2002a-0-48549d615a35c"" + ["Accept-Ranges"]=> + string(5) "bytes" + ["Content-Length"]=> + int(0) + ["Vary"]=> + string(15) "Accept-Encoding" + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(10) "text/plain" + ["X-Original-Content-Length"]=> + string(1) "0" +} +GET /default/empty.txt HTTP/1.1 +Host: localhost +Connection: close +Content-Length: 0 +HTTP/1.1 200 OK +Date: Thu, 26 Aug 2010 09:55:09 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT +Etag: "2002a-0-48549d615a35c" +Accept-Ranges: bytes +Vary: Accept-Encoding +Content-Length: 0 +Connection: close +Content-Type: text/plain +X-Original-Content-Length: 20 +X-Original-Content-Encoding: gzip +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(11) { + ["Date"]=> + string(29) "Thu, 26 Aug 2010 09:55:09 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["Last-Modified"]=> + string(29) "Wed, 28 Apr 2010 10:54:37 GMT" + ["Etag"]=> + string(23) ""2002a-0-48549d615a35c"" + ["Accept-Ranges"]=> + string(5) "bytes" + ["Vary"]=> + string(15) "Accept-Encoding" + ["Content-Length"]=> + int(0) + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(10) "text/plain" + ["X-Original-Content-Length"]=> + string(2) "20" + ["X-Original-Content-Encoding"]=> + string(4) "gzip" +} +GET /default/empty.txt HTTP/1.1 +Host: localhost +Accept-Encoding: gzip +Connection: close +Content-Length: 0 +HTTP/1.1 200 OK +Date: Thu, 26 Aug 2010 11:41:02 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +X-Powered-By: PHP/5.3.3 +Vary: Accept-Encoding +Connection: close +Content-Type: text/html +X-Original-Transfer-Encoding: chunked +Content-Length: 0 +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(8) { + ["Date"]=> + string(29) "Thu, 26 Aug 2010 11:41:02 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["X-Powered-By"]=> + string(9) "PHP/5.3.3" + ["Vary"]=> + string(15) "Accept-Encoding" + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(9) "text/html" + ["X-Original-Transfer-Encoding"]=> + string(7) "chunked" + ["Content-Length"]=> + int(0) +} +GET /default/empty.php HTTP/1.1 +Connection: close +Host: localhost +Content-Length: 0 +HTTP/1.1 200 OK +Date: Thu, 26 Aug 2010 12:51:28 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +Vary: Accept-Encoding +Connection: close +Content-Type: text/plain +X-Original-Transfer-Encoding: chunked +Content-Length: 14 + +Hello, World! +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(7) { + ["Date"]=> + string(29) "Thu, 26 Aug 2010 12:51:28 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["Vary"]=> + string(15) "Accept-Encoding" + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(10) "text/plain" + ["X-Original-Transfer-Encoding"]=> + string(7) "chunked" + ["Content-Length"]=> + int(14) +} +GET /cgi-bin/chunked.sh HTTP/1.1 +Host: localhost +Connection: close +Content-Length: 0 +--- +HTTP/1.1 200 OK +Date: Wed, 25 Aug 2010 12:11:44 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT +Etag: "2002a-0-48549d615a35c" +Accept-Ranges: bytes +Content-Length: 0 +Vary: Accept-Encoding +Connection: close +Content-Type: text/plain +X-Original-Content-Length: 0 +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(10) { + ["Date"]=> + string(29) "Wed, 25 Aug 2010 12:11:44 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["Last-Modified"]=> + string(29) "Wed, 28 Apr 2010 10:54:37 GMT" + ["Etag"]=> + string(23) ""2002a-0-48549d615a35c"" + ["Accept-Ranges"]=> + string(5) "bytes" + ["Content-Length"]=> + int(0) + ["Vary"]=> + string(15) "Accept-Encoding" + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(10) "text/plain" + ["X-Original-Content-Length"]=> + string(1) "0" +} +GET /default/empty.txt HTTP/1.1 +Host: localhost +Connection: close +Content-Length: 0 +HTTP/1.1 200 OK +Date: Thu, 26 Aug 2010 09:55:09 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT +Etag: "2002a-0-48549d615a35c" +Accept-Ranges: bytes +Vary: Accept-Encoding +Content-Length: 0 +Connection: close +Content-Type: text/plain +X-Original-Content-Length: 20 +X-Original-Content-Encoding: gzip +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(11) { + ["Date"]=> + string(29) "Thu, 26 Aug 2010 09:55:09 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["Last-Modified"]=> + string(29) "Wed, 28 Apr 2010 10:54:37 GMT" + ["Etag"]=> + string(23) ""2002a-0-48549d615a35c"" + ["Accept-Ranges"]=> + string(5) "bytes" + ["Vary"]=> + string(15) "Accept-Encoding" + ["Content-Length"]=> + int(0) + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(10) "text/plain" + ["X-Original-Content-Length"]=> + string(2) "20" + ["X-Original-Content-Encoding"]=> + string(4) "gzip" +} +GET /default/empty.txt HTTP/1.1 +Host: localhost +Accept-Encoding: gzip +Connection: close +Content-Length: 0 +HTTP/1.1 200 OK +Date: Thu, 26 Aug 2010 11:41:02 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +X-Powered-By: PHP/5.3.3 +Vary: Accept-Encoding +Connection: close +Content-Type: text/html +X-Original-Transfer-Encoding: chunked +Content-Length: 0 +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(8) { + ["Date"]=> + string(29) "Thu, 26 Aug 2010 11:41:02 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["X-Powered-By"]=> + string(9) "PHP/5.3.3" + ["Vary"]=> + string(15) "Accept-Encoding" + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(9) "text/html" + ["X-Original-Transfer-Encoding"]=> + string(7) "chunked" + ["Content-Length"]=> + int(0) +} +GET /default/empty.php HTTP/1.1 +Connection: close +Host: localhost +Content-Length: 0 +HTTP/1.1 200 OK +Date: Thu, 26 Aug 2010 12:51:28 GMT +Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6 +Vary: Accept-Encoding +Connection: close +Content-Type: text/plain +X-Original-Transfer-Encoding: chunked +Content-Length: 14 + +Hello, World! +string(3) "1.1" +bool(true) +int(200) +string(2) "OK" +array(7) { + ["Date"]=> + string(29) "Thu, 26 Aug 2010 12:51:28 GMT" + ["Server"]=> + string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" + ["Vary"]=> + string(15) "Accept-Encoding" + ["Connection"]=> + string(5) "close" + ["Content-Type"]=> + string(10) "text/plain" + ["X-Original-Transfer-Encoding"]=> + string(7) "chunked" + ["Content-Length"]=> + int(14) +} +GET /cgi-bin/chunked.sh HTTP/1.1 +Host: localhost +Connection: close +Content-Length: 0 +Done diff --git a/tests/message002.phpt b/tests/message002.phpt new file mode 100644 index 0000000..06d9e1b --- /dev/null +++ b/tests/message002.phpt @@ -0,0 +1,91 @@ +--TEST-- +env request message +--SKIPIF-- + +--POST_RAW-- +Content-Type: test/something +b=c +--ENV-- +HTTP_X_TEST=test +--COOKIE-- +foo=bar +--FILE-- + +echo "Test\n"; + +use http\env\Request as HttpEnvRequest; + +$m = new HttpEnvRequest(); + +var_dump($m); + +echo "Message->toString\n"; +echo $m,"\n"; + +echo "Body->toString\n"; +var_dump((string)$m->getBody()); + +echo "stream\n"; +var_dump(file_get_contents("php://input")); + +echo "Done\n"; +--EXPECTF-- +Test +object(%s)#%d (12) { + ["type":protected]=> + int(1) + ["body":protected]=> + object(http\Message\Body)#%d (0) { + } + ["requestMethod":protected]=> + string(4) "POST" + ["requestUrl":protected]=> + string(0) "" + ["responseStatus":protected]=> + string(0) "" + ["responseCode":protected]=> + int(0) + ["httpVersion":protected]=> + string(3) "1.1" + ["headers":protected]=> + array(4) { + ["X-Test"]=> + string(4) "test" + ["Content-Length"]=> + string(1) "3" + ["Content-Type"]=> + string(14) "test/something" + ["Cookie"]=> + string(7) "foo=bar" + } + ["parentMessage":protected]=> + NULL + ["query":protected]=> + object(http\QueryString)#2 (1) { + ["queryArray":"http\QueryString":private]=> + array(0) { + } + } + ["form":protected]=> + object(http\QueryString)#3 (1) { + ["queryArray":"http\QueryString":private]=> + array(0) { + } + } + ["files":protected]=> + array(0) { + } +} +Message->toString +POST / HTTP/1.1%a +X-Test: test%a +Content-Length: 3%a +Content-Type: test/something%a +Cookie: foo=bar%a +%a +b=c +Body->toString +string(3) "b=c" +stream +string(3) "b=c" +Done diff --git a/tests/message003.phpt b/tests/message003.phpt new file mode 100644 index 0000000..69be990 --- /dev/null +++ b/tests/message003.phpt @@ -0,0 +1,79 @@ +--TEST-- +multipart message +--SKIPIF-- + include "skipif.inc"; +--FILE-- + +$m = new http\Message(fopen(__DIR__."/data/message_r_multipart_put.txt","rb")); +if ($m->isMultipart($boundary)) { + var_dump($boundary); + + foreach ($m->splitMultipartBody() as $i => $mm) { + echo "==$i==\n",$mm,"===\n"; + } +} +?> +DONE +--EXPECTF-- +string(40) "----------------------------6e182425881c" +==%d== +Content-Disposition: form-data; name="composer"; filename="composer.json" +Content-Type: application/octet-stream +Content-Length: 567 + +{ + "name": "mike_php_net/autocracy", + "type": "library", + "description": "http\\Controller preserves your autocracy", + "keywords": ["http", "controller", "pecl", "pecl_http"], + "homepage": "http://github.com/mike-php-net/autocracy", + "license": "BSD-2", + "authors": [ + { + "name": "Michael Wallner", + "email": "mike@php.net" + } + ], + "require": { + "php": ">=5.4.0", + "pecl/pecl_http": "2.*" + }, + "autoload": { + "psr-0": { + "http\\Controller": "lib" + } + } +} + +=== +==%d== +Content-Disposition: form-data; name="LICENSE"; filename="LICENSE" +Content-Type: application/octet-stream +Content-Length: 1354 + +Copyright (c) 2011-2012, Michael Wallner . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +=== +DONE diff --git a/tests/HttpMessage_007.phpt b/tests/message004.phpt similarity index 70% rename from tests/HttpMessage_007.phpt rename to tests/message004.phpt index 02d4de0..914a8da 100644 --- a/tests/HttpMessage_007.phpt +++ b/tests/message004.phpt @@ -1,46 +1,68 @@ --TEST-- -HttpMessage::reverse() +message reversal --SKIPIF-- +include "skip.inc"; --FILE-- toString(true); +echo newHttpMessage($s)->toString(true); echo "===\n"; -echo HttpMessage::fromString($s)->reverse()->toString(true); +echo newHttpMessage($s)->reverse()->toString(true); -$m = new HttpMessage($s); +$m = newHttpMessage($s); $r = $m->reverse(); unset($m); var_dump($r->count()); echo $r->toString(true); -echo "Done\n"; ?> +DONE --EXPECTF-- -%aTEST GET /first HTTP/1.1 + HTTP/1.1 200 Ok-first + GET /second HTTP/1.1 + HTTP/1.1 200 Ok-second + GET /third HTTP/1.1 + HTTP/1.1 200 Ok-third + === HTTP/1.1 200 Ok-third + GET /third HTTP/1.1 + HTTP/1.1 200 Ok-second + GET /second HTTP/1.1 + HTTP/1.1 200 Ok-first + GET /first HTTP/1.1 + int(6) HTTP/1.1 200 Ok-third + GET /third HTTP/1.1 + HTTP/1.1 200 Ok-second + GET /second HTTP/1.1 + HTTP/1.1 200 Ok-first + GET /first HTTP/1.1 -Done + +DONE + diff --git a/tests/message005.phpt b/tests/message005.phpt new file mode 100644 index 0000000..6f7a546 --- /dev/null +++ b/tests/message005.phpt @@ -0,0 +1,32 @@ +--TEST-- +message cloning +--SKIPIF-- +setType(http\Message::TYPE_REQUEST); +$cpy->setHeaders(array("Numbers" => array(1,2,3,4.5))); + +echo $msg; +echo "\n===\n"; +echo $cpy; + +?> +DONE +--EXPECTF-- +HTTP/1.1 200 Ok +String: foobar + +=== +UNKNOWN / HTTP/1.1 +Numbers: 1, 2, 3, 4.5 +DONE diff --git a/tests/message006.phpt b/tests/message006.phpt new file mode 100644 index 0000000..52e534d --- /dev/null +++ b/tests/message006.phpt @@ -0,0 +1,47 @@ +--TEST-- +message var_dump with inherited property with increased access level +--SKIPIF-- + +--FILE-- +headers["foo"] = "bar"; +var_dump($m); + +?> +DONE +--EXPECTF-- +Test +object(c)#%d (9) { + ["headers"]=> + array(1) { + ["foo"]=> + string(3) "bar" + } + ["type":protected]=> + int(0) + ["body":protected]=> + object(http\Message\Body)#%d (0) { + } + ["requestMethod":protected]=> + string(0) "" + ["requestUrl":protected]=> + string(0) "" + ["responseStatus":protected]=> + string(0) "" + ["responseCode":protected]=> + int(0) + ["httpVersion":protected]=> + string(3) "1.1" + ["parentMessage":protected]=> + NULL +} +DONE diff --git a/tests/message007.phpt b/tests/message007.phpt new file mode 100644 index 0000000..478f411 --- /dev/null +++ b/tests/message007.phpt @@ -0,0 +1,27 @@ +--TEST-- +message to stream +--SKIPIF-- + +--FILE-- +addHeader("Content-Type", "text/plain"); +$m->getBody()->append("this\nis\nthe\ntext"); + +$f = tmpfile(); +$m->toStream($f); +rewind($f); +var_dump((string) $m === stream_get_contents($f)); +fclose($f); + +?> +Done +--EXPECT-- +Test +bool(true) +Done diff --git a/tests/message008.phpt b/tests/message008.phpt new file mode 100644 index 0000000..3f5154d --- /dev/null +++ b/tests/message008.phpt @@ -0,0 +1,29 @@ +--TEST-- +message to callback +--SKIPIF-- + +--FILE-- +addHeader("Content-Type", "text/plain"); +$m->getBody()->append("this\nis\nthe\ntext"); + +$d = new http\Encoding\Stream\Deflate; +$s = ""; +$m->toCallback(function ($m, $data) use ($d, &$s) { + $s.=$d->update($data); +}); +$s.=$d->finish(); +var_dump($m->toString() === http\Encoding\Stream\Inflate::decode($s)); + +?> +Done +--EXPECT-- +Test +bool(true) +Done diff --git a/tests/message009.phpt b/tests/message009.phpt new file mode 100644 index 0000000..34a923f --- /dev/null +++ b/tests/message009.phpt @@ -0,0 +1,149 @@ +--TEST-- +message properties +--SKIPIF-- + +--FILE-- +$prop; + case "set": + $this->$prop = current($args); + break; + } + } + } +} + +$test = new message; +var_dump(0 === $test->testGetType()); +var_dump(null === $test->testGetBody()); +var_dump(null === $test->testGetRequestMethod()); +var_dump(null === $test->testGetRequestUrl()); +var_dump(null === $test->testGetResponseStatus()); +var_dump(null === $test->testGetResponseCode()); +var_dump("1.1" === $test->testGetHttpVersion()); +var_dump(array() === $test->testGetHeaders()); +var_dump(null === $test->testGetParentMessage()); +$test->testSetType(http\Message::TYPE_REQUEST); +var_dump(http\Message::TYPE_REQUEST === $test->testGetType()); +var_dump(http\Message::TYPE_REQUEST === $test->getType()); +$body = new http\Message\Body; +$test->testSetBody($body); +var_dump($body === $test->testGetBody()); +var_dump($body === $test->getBody()); +$file = fopen(__FILE__,"r"); +$test->testSetBody($file); +var_dump($file === $test->testGetBody()->getResource()); +var_dump($file === $test->getBody()->getResource()); +$test->testSetBody("data"); +var_dump("data" === (string) $test->testGetBody()); +var_dump("data" === (string) $test->getBody()); +$test->testSetRequestMethod("HEAD"); +var_dump("HEAD" === $test->testGetRequestMethod()); +var_dump("HEAD" === $test->getRequestMethod()); +$test->testSetRequestUrl("/"); +var_dump("/" === $test->testGetRequestUrl()); +var_dump("/" === $test->getRequestUrl()); +var_dump("HEAD / HTTP/1.1" === $test->getInfo()); +$test->testSetType(http\Message::TYPE_RESPONSE); +$test->setResponseStatus("Created"); +var_dump("Created" === $test->testGetResponseStatus()); +var_dump("Created" === $test->getResponseStatus()); +$test->setResponseCode(201); +var_dump(201 === $test->testGetResponseCode()); +var_dump(201 === $test->getResponseCode()); +$test->testSetResponseStatus("Ok"); +var_dump("Ok" === $test->testGetResponseStatus()); +var_dump("Ok" === $test->getResponseStatus()); +$test->testSetResponseCode(200); +var_dump(200 === $test->testGetResponseCode()); +var_dump(200 === $test->getResponseCode()); +$test->testSetHttpVersion("1.0"); +var_dump("1.0" === $test->testGetHttpVersion()); +var_dump("1.0" === $test->getHttpVersion()); +var_dump("HTTP/1.0 200 OK" === $test->getInfo()); +$test->setHttpVersion("1.1"); +var_dump("1.1" === $test->testGetHttpVersion()); +var_dump("1.1" === $test->getHttpVersion()); +var_dump("HTTP/1.1 200 OK" === $test->getInfo()); +$test->setInfo("HTTP/1.1 201 Created"); +var_dump("Created" === $test->testGetResponseStatus()); +var_dump("Created" === $test->getResponseStatus()); +var_dump(201 === $test->testGetResponseCode()); +var_dump(201 === $test->getResponseCode()); +var_dump("1.1" === $test->testGetHttpVersion()); +var_dump("1.1" === $test->getHttpVersion()); +$test->testSetHeaders(array("Foo" => "bar")); +var_dump(array("Foo" => "bar") === $test->testGetHeaders()); +var_dump(array("Foo" => "bar") === $test->getHeaders()); +var_dump("bar" === $test->getHeader("foo")); +var_dump(false === $test->getHeader("bar")); +$parent = new message; +$test->testSetParentMessage($parent); +var_dump($parent === $test->testGetParentMessage()); +var_dump($parent === $test->getParentMessage()); + +?> +Done +--EXPECT-- +Test +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +Done diff --git a/tests/message010.phpt b/tests/message010.phpt new file mode 100644 index 0000000..5a51510 --- /dev/null +++ b/tests/message010.phpt @@ -0,0 +1,26 @@ +--TEST-- +message body +--SKIPIF-- + +--FILE-- +append("foo"); +$m->addBody($body); +$body = new http\Message\Body; +$body->append("bar"); +$m->addBody($body); +var_dump("foobar" === (string) $m->getBody()); + +?> +Done +--EXPECT-- +Test +bool(true) +Done diff --git a/tests/message011.phpt b/tests/message011.phpt new file mode 100644 index 0000000..53aa992 --- /dev/null +++ b/tests/message011.phpt @@ -0,0 +1,77 @@ +--TEST-- +message headers +--SKIPIF-- + +--INI-- +date.timezone=UTC +--FILE-- +str = $str; + } + function __toString() { + return (string) $this->str; + } +} + +$m = new http\Message; +$m->addHeaders(array("foo"=>"bar","bar"=>"foo")); +var_dump(array("Foo"=>"bar", "Bar"=>"foo") === $m->getHeaders()); +$m->addHeaders(array("key"=>"val","more"=>"Stuff")); +var_dump(array("Foo"=>"bar", "Bar"=>"foo","Key"=>"val","More"=>"Stuff") === $m->getHeaders()); +$m = new http\Message("GET / HTTP/1.1"); +$m->addHeader("Accept", "text/html"); +$m->addHeader("Accept", "text/xml;q=0"); +$m->addHeader("Accept", "text/plain;q=0.5"); +var_dump( + "GET / HTTP/1.1\r\n". + "Accept: text/html, text/xml;q=0, text/plain;q=0.5\r\n" === + $m->toString() +); +$m = new http\Message("HTTP/1.1 200 Ok"); +$m->addHeader("Bool", true); +$m->addHeader("Int", 123); +$m->addHeader("Float", 1.23); +$m->addHeader("Array", array(1,2,3)); +$m->addHeader("Object", new strval("test")); +$m->addHeader("Set-Cookie", + array( + array( + "cookies" => array("foo" => "bar"), + "expires" => date_create("2012-12-31 22:59:59 GMT")->format( + DateTime::COOKIE + ), + "path" => "/somewhere" + ) + ) +); +$m->addHeader("Set-Cookie", "val=0"); + +var_dump( + "HTTP/1.1 200 Ok\r\n". + "Bool: true\r\n". + "Int: 123\r\n". + "Float: 1.23\r\n". + "Array: 1, 2, 3\r\n". + "Object: test\r\n". + "Set-Cookie: foo=bar; path=/somewhere; expires=Mon, 31 Dec 2012 22:59:59 GMT; \r\n". + "Set-Cookie: val=0\r\n" === + $m->toString() +); + +?> +Done +--EXPECT-- +Test +bool(true) +bool(true) +bool(true) +bool(true) +Done diff --git a/tests/message012.phpt b/tests/message012.phpt new file mode 100644 index 0000000..5f46c48 --- /dev/null +++ b/tests/message012.phpt @@ -0,0 +1,34 @@ +--TEST-- +message part +--SKIPIF-- + +--FILE-- +addHeader("Content-Type", "text/plain"); +$p->getBody()->append("data"); + +$m = new http\Message("HTTP/1.1 200"); +$m->getBody()->addPart($p); +echo $m; + +?> +Done +--EXPECTF-- +Test +HTTP/1.1 200 +Content-Length: %d +Content-Type: multipart/form-data; boundary="%x.%x" + +--%x.%x +Content-Type: text/plain +Content-Length: 4 + +data +--%x.%x-- +Done diff --git a/tests/message013.phpt b/tests/message013.phpt new file mode 100644 index 0000000..8a192a5 --- /dev/null +++ b/tests/message013.phpt @@ -0,0 +1,33 @@ +--TEST-- +message detach +--SKIPIF-- + +--FILE-- +detach(); +var_dump(3 === count($m)); +var_dump(1 === count($d)); + +var_dump("HTTP/1.1 302 Found\r\n\r\n" === $d->toString(true)); + +?> +Done +--EXPECTF-- +Test +bool(true) +bool(true) +bool(true) +bool(true) +Done diff --git a/tests/message014.phpt b/tests/message014.phpt new file mode 100644 index 0000000..485c47f --- /dev/null +++ b/tests/message014.phpt @@ -0,0 +1,39 @@ +--TEST-- +message prepend +--SKIPIF-- + +--FILE-- +prepend($p); + $p = $m; +} + +var_dump( + "HTTP/1.1 200\r\n\r\n". + "HTTP/1.1 201\r\n\r\n". + "HTTP/1.1 202\r\n\r\n". + "HTTP/1.1 203\r\n\r\n". + "HTTP/1.1 204\r\n\r\n". + "HTTP/1.1 205\r\n\r\n". + "HTTP/1.1 206\r\n\r\n". + "HTTP/1.1 207\r\n\r\n". + "HTTP/1.1 208\r\n\r\n" === + $m->toString(true) +); + +?> +Done +--EXPECTF-- +Test +bool(true) +Done diff --git a/tests/message015.phpt b/tests/message015.phpt new file mode 100644 index 0000000..e9bd846 --- /dev/null +++ b/tests/message015.phpt @@ -0,0 +1,49 @@ +--TEST-- +message errors +--SKIPIF-- + +--FILE-- +setRequestUrl("/foo"); +} catch (http\Exception $e) { + echo $e->getMessage(),"\n"; +} +$m->setType(http\Message::TYPE_REQUEST); +try { + $m->setRequestUrl(""); +} catch (http\Exception $e) { + echo $e->getMessage(),"\n"; +} + +$m = new http\Message; +try { + $m->getParentMessage(); + die("unreached"); +} catch (http\Exception $e) { + echo $e->getMessage(),"\n"; +} + +$m = new http\Message("HTTP/1.1 200\r\nHTTP/1.1 201"); +try { + $m->prepend($m->getParentMessage()); + die("unreached"); +} catch (http\Exception $e) { + echo $e->getMessage(),"\n"; +} + +?> +Done +--EXPECTF-- +Test +http\Message is not of type request +Cannot set http\Message's request url to an empty string +http\Message has not parent message +Cannot prepend a message located within the same message chain +Done diff --git a/tests/negotiate001.phpt b/tests/negotiate001.phpt new file mode 100644 index 0000000..d384b87 --- /dev/null +++ b/tests/negotiate001.phpt @@ -0,0 +1,128 @@ +--TEST-- +negotiate +--SKIPIF-- + +--ENV-- +HTTP_ACCEPT=text/html,text/plain,text/xml;q=0.1,image/*;q=0.1,*/*;q=0 +HTTP_ACCEPT_CHARSET=utf-8,iso-8859-1;q=0.8,iso-8859-15;q=0 +HTTP_ACCEPT_ENCODING=gzip,deflate;q=0 +HTTP_ACCEPT_LANGUAGE=de-DE,de-AT;q=0.9,en;q=0.8,fr;q=0 +--FILE-- +CONTENT TYPE + + + +CHARSET + + + +ENCODING + + + +LANGUAGE + + + +CUSTOM + + +$cc = http\Env::negotiate("a, a.b;q=0.9, c.d;q=0, *.* ; q=0.1", + array("a.x", "c.d", "c.e", "a.b"), ".", $ccr); +echo "$cc: "; print_r($ccr); +?> +DONE +--EXPECT-- +CONTENT TYPE + +text/html: Array +( + [text/html] => 0.99 + [text/xml] => 0.1 +) +text/xml: Array +( + [text/xml] => 0.1 +) +text/json: Array +( +) + +CHARSET + +utf-8: Array +( + [utf-8] => 0.99 + [iso-8859-1] => 0.8 +) +iso-8859-1: Array +( + [iso-8859-1] => 0.8 +) +utf-16: Array +( +) + +ENCODING + +gzip: Array +( + [gzip] => 0.99 +) +: Array +( +) + +LANGUAGE + +de: Array +( + [de] => 0.99 + [en] => 0.8 +) +de-DE: Array +( + [de-DE] => 0.99 + [de-AT] => 0.9 + [en] => 0.8 +) +en: Array +( + [en] => 0.8 +) + +CUSTOM + +a.b: Array +( + [a.b] => 0.9 + [c.e] => 0.1 + [a.x] => 0.1 +) +DONE diff --git a/tests/negotiation_001.phpt b/tests/negotiation_001.phpt deleted file mode 100644 index 3c2a6d0..0000000 --- a/tests/negotiation_001.phpt +++ /dev/null @@ -1,64 +0,0 @@ ---TEST-- -negotiation ---SKIPIF-- - ---ENV-- -HTTP_ACCEPT=application/xml, application/xhtml+xml, text/html ; q = .8 -HTTP_ACCEPT_LANGUAGE=de-AT,de-DE;q=0.8,en-GB;q=0.3,en-US;q=0.2 -HTTP_ACCEPT_CHARSET=ISO-8859-1,utf-8;q=0.7,*;q=0.7 ---FILE-- - ---EXPECTF-- -%aTEST -string(2) "de" -string(2) "de" -string(10) "iso-8859-1" -string(10) "iso-8859-1" -string(21) "application/xhtml+xml" -string(21) "application/xhtml+xml" -string(7) "unknown" -string(7) "unknown" -string(7) "unknown" -Array -( - [de] => 900 - [en] => 0.27 -) -Array -( - [iso-8859-1] => 1000 - [utf-8] => 0.7 -) -Array -( - [application/xhtml+xml] => 999 - [text/html] => 0.8 -) -Done diff --git a/tests/ob_deflatehandler_001.phpt b/tests/ob_deflatehandler_001.phpt deleted file mode 100644 index bed6803..0000000 --- a/tests/ob_deflatehandler_001.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -ob_deflatehandler ---SKIPIF-- - ---ENV-- -HTTP_ACCEPT_ENCODING=gzip ---FILE-- - ---EXPECTF-- -%a -Content-Encoding: gzip -Vary: Accept-Encoding -%a - diff --git a/tests/ob_inflatehandler_001.phpt b/tests/ob_inflatehandler_001.phpt deleted file mode 100644 index 5d352b4..0000000 --- a/tests/ob_inflatehandler_001.phpt +++ /dev/null @@ -1,16 +0,0 @@ ---TEST-- -ob_inflatehandler ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST - diff --git a/tests/params001.phpt b/tests/params001.phpt new file mode 100644 index 0000000..ac52bf7 --- /dev/null +++ b/tests/params001.phpt @@ -0,0 +1,40 @@ +--TEST-- +header params +--SKIPIF-- + array("charset" => "iso-8859-1")); + +var_dump( + isset($ct["text/html"]), + isset($ct["text/json"]), + $ct["text/json"]["arguments"]["charset"] +); + +var_dump((string) $ct); + +echo "Done\n"; +--EXPECTF-- +Test +bool(true) +bool(false) +string(5) "utf-8" +bool(false) +bool(true) +string(10) "iso-8859-1" +string(%d) "text/json;charset=iso-8859-1" +Done diff --git a/tests/params002.phpt b/tests/params002.phpt new file mode 100644 index 0000000..95bc7ac --- /dev/null +++ b/tests/params002.phpt @@ -0,0 +1,58 @@ +--TEST-- +query parser +--SKIPIF-- + +--FILE-- + +DONE +--EXPECTF-- +object(http\Params)#%d (5) { + ["params"]=> + array(2) { + ["foo"]=> + array(2) { + ["value"]=> + string(3) "bar" + ["arguments"]=> + array(0) { + } + } + ["arr"]=> + array(2) { + ["value"]=> + array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "2" + } + ["arguments"]=> + array(0) { + } + } + } + ["param_sep"]=> + array(2) { + [0]=> + string(1) "&" + [1]=> + string(1) ";" + } + ["arg_sep"]=> + string(0) "" + ["val_sep"]=> + string(1) "=" + ["flags"]=> + int(12) +} +foo=bar&arr%5B0%5D=1&arr%5B1%5D=2 +DONE + diff --git a/tests/parse_cookie_001.phpt b/tests/parse_cookie_001.phpt deleted file mode 100644 index 2668b0e..0000000 --- a/tests/parse_cookie_001.phpt +++ /dev/null @@ -1,41 +0,0 @@ ---TEST-- -parse cookie ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -object(stdClass)%a { - ["cookies"]=> - array(3) { - ["name"]=> - string(5) "value" - ["foo"]=> - string(7) "bar"baz" - ["hey"]=> - string(6) "got"it" - } - ["extras"]=> - array(1) { - ["comment"]=> - string(0) "" - } - ["flags"]=> - int(32) - ["expires"]=> - int(1) - ["path"]=> - string(1) "/" - ["domain"]=> - string(0) "" -} -Done diff --git a/tests/parse_cookie_002.phpt b/tests/parse_cookie_002.phpt deleted file mode 100644 index 220f4e9..0000000 --- a/tests/parse_cookie_002.phpt +++ /dev/null @@ -1,80 +0,0 @@ ---TEST-- -parse cookie ---SKIPIF-- - ---FILE-- -cookies['foo']); -var_dump(http_parse_cookie('foo;')->cookies['foo']); -var_dump(http_parse_cookie('foo ')->cookies['foo']); -var_dump(http_parse_cookie('foo ;')->cookies['foo']); -var_dump(http_parse_cookie('foo ; ')->cookies['foo']); -var_dump(http_parse_cookie('foo=')->cookies['foo']); -var_dump(http_parse_cookie('foo=;')->cookies['foo']); -var_dump(http_parse_cookie('foo =')->cookies['foo']); -var_dump(http_parse_cookie('foo =;')->cookies['foo']); -var_dump(http_parse_cookie('foo= ')->cookies['foo']); -var_dump(http_parse_cookie('foo= ;')->cookies['foo']); - -var_dump(http_parse_cookie('foo=1')->cookies['foo']); -var_dump(http_parse_cookie('foo=1;')->cookies['foo']); -var_dump(http_parse_cookie('foo=1 ;')->cookies['foo']); -var_dump(http_parse_cookie('foo= 1;')->cookies['foo']); -var_dump(http_parse_cookie('foo = 1;')->cookies['foo']); -var_dump(http_parse_cookie('foo = 1 ;')->cookies['foo']); -var_dump(http_parse_cookie('foo=1')->cookies['foo']); -var_dump(http_parse_cookie('foo= 1')->cookies['foo']); - -var_dump(http_parse_cookie('foo="1"')->cookies['foo']); -var_dump(http_parse_cookie('foo="1" ')->cookies['foo']); -var_dump(http_parse_cookie('foo="1";')->cookies['foo']); -var_dump(http_parse_cookie('foo = "1" ;')->cookies['foo']); -var_dump(http_parse_cookie('foo= "1" ')->cookies['foo']); - -var_dump(http_parse_cookie('foo=""')->cookies['foo']); -var_dump(http_parse_cookie('foo="\""')->cookies['foo']); -var_dump(http_parse_cookie('foo=" "')->cookies['foo']); -var_dump(http_parse_cookie('foo= "')->cookies['foo']); -var_dump(http_parse_cookie('foo=" ')->cookies['foo']); -var_dump(http_parse_cookie('foo= " ')->cookies['foo']); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -string(0) "" -string(0) "" -string(0) "" -string(0) "" -string(0) "" -string(0) "" -string(0) "" -string(0) "" -string(0) "" -string(0) "" -string(0) "" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(1) "1" -string(0) "" -string(1) """ -string(1) " " -string(1) """ -string(1) """ -string(1) """ -Done diff --git a/tests/parse_headers_001.phpt b/tests/parse_headers_001.phpt deleted file mode 100644 index c81e883..0000000 --- a/tests/parse_headers_001.phpt +++ /dev/null @@ -1,41 +0,0 @@ ---TEST-- -http_parse_headers() ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -Array -( - [Host] => Array - ( - [0] => localhost - [1] => ambigious - ) - - [Nospace] => here - [Muchspace] => there - [Empty] => - [Empty2] => - [Folded] => one - two - three -) - diff --git a/tests/parse_message_001.phpt b/tests/parse_message_001.phpt deleted file mode 100644 index a252d63..0000000 --- a/tests/parse_message_001.phpt +++ /dev/null @@ -1,18 +0,0 @@ ---TEST-- -http_parse_message() ---SKIPIF-- - ---FILE-- -body; -echo "Done\n"; ---EXPECTF-- -%aTEST -%aThe document has moved%a -Done diff --git a/tests/parse_message_002.phpt b/tests/parse_message_002.phpt deleted file mode 100644 index 95a2815..0000000 --- a/tests/parse_message_002.phpt +++ /dev/null @@ -1,39 +0,0 @@ ---TEST-- -identity encoding trap ---SKIPIF-- - ---FILE-- - 2 - [httpVersion] => 1.1 - [responseCode] => 200 - [responseStatus] => Ok - [headers] => Array - ( - [Transfer-Encoding] => identity - [Content-Length] => 3 - [Content-Type] => text/plain - ) - - [body] => Hi! - [parentMessage] => -) -Done diff --git a/tests/parse_message_003.phpt b/tests/parse_message_003.phpt deleted file mode 100644 index 3ceafe9..0000000 --- a/tests/parse_message_003.phpt +++ /dev/null @@ -1,31 +0,0 @@ ---TEST-- -content range message ---SKIPIF-- - ---FILE-- -body); - -$message = -"HTTP/1.1 200 Ok\n". -"Content-Range: bytes 0-1/1\n\n". -"X\n"; - -$msg = http_parse_message($message); - -echo "Done\n"; ---EXPECTF-- -%aTEST -string(2) "OK" -%a Invalid Content-Range header: bytes 0-1/1 in%a -Done diff --git a/tests/parse_message_004.phpt b/tests/parse_message_004.phpt deleted file mode 100644 index 5ce6048..0000000 --- a/tests/parse_message_004.phpt +++ /dev/null @@ -1,115 +0,0 @@ ---TEST-- -http_parse_message() recursive ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -object(stdClass)%a { - ["type"]=> - int(2) - ["httpVersion"]=> - float(1.1) - ["responseCode"]=> - int(200) - ["responseStatus"]=> - string(2) "Ok" - ["headers"]=> - array(2) { - ["Server"]=> - string(9) "Funky/1.0" - ["Content-Length"]=> - string(2) "10" - } - ["body"]=> - string(10) "1234567890" - ["parentMessage"]=> - object(stdClass)%a { - ["type"]=> - int(1) - ["httpVersion"]=> - float(1.1) - ["requestMethod"]=> - string(3) "GET" - ["requestUrl"]=> - string(1) "/" - ["headers"]=> - array(2) { - ["Host"]=> - string(15) "www.example.com" - ["Accept"]=> - string(3) "*/*" - } - ["body"]=> - string(0) "" - ["parentMessage"]=> - object(stdClass)%a { - ["type"]=> - int(2) - ["httpVersion"]=> - float(1.1) - ["responseCode"]=> - int(200) - ["responseStatus"]=> - string(2) "Ok" - ["headers"]=> - array(2) { - ["Server"]=> - string(9) "Funky/1.0" - ["Content-Length"]=> - string(2) "10" - } - ["body"]=> - string(0) "" - ["parentMessage"]=> - object(stdClass)%a { - ["type"]=> - int(1) - ["httpVersion"]=> - float(1.1) - ["requestMethod"]=> - string(4) "HEAD" - ["requestUrl"]=> - string(1) "/" - ["headers"]=> - array(2) { - ["Host"]=> - string(15) "www.example.com" - ["Accept"]=> - string(3) "*/*" - } - ["body"]=> - string(0) "" - ["parentMessage"]=> - NULL - } - } - } -} -Done diff --git a/tests/parse_message_005.phpt b/tests/parse_message_005.phpt deleted file mode 100644 index e07db87..0000000 --- a/tests/parse_message_005.phpt +++ /dev/null @@ -1,60 +0,0 @@ ---TEST-- -http_parse_message() content range header w/(o) = ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -stdClass Object -( - [type] => 2 - [httpVersion] => 1.1 - [responseCode] => 206 - [responseStatus] => - [headers] => Array - ( - [Server] => Funky/1.0 - [Content-Range] => bytes 0-0/100 - ) - - [body] => 1 - [parentMessage] => stdClass Object - ( - [type] => 2 - [httpVersion] => 1.1 - [responseCode] => 206 - [responseStatus] => - [headers] => Array - ( - [Server] => Funky/1.0 - [Content-Range] => bytes: 0-0/100 - ) - - [body] => 1 - [parentMessage] => - ) - -) -Done diff --git a/tests/parse_message_006.phpt b/tests/parse_message_006.phpt deleted file mode 100644 index d1d435f..0000000 --- a/tests/parse_message_006.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -mixed EOL trap ---SKIPIF-- - ---FILE-- - 2 - [httpVersion] => 1.1 - [responseCode] => 200 - [responseStatus] => Ok - [headers] => Array - ( - [Header] => Value - [Connection] => close - ) - - [body] => Bug! - [parentMessage] => -) -Done diff --git a/tests/parse_params_001.phpt b/tests/parse_params_001.phpt deleted file mode 100644 index ab5a5b2..0000000 --- a/tests/parse_params_001.phpt +++ /dev/null @@ -1,75 +0,0 @@ ---TEST-- -http_parse_params ---SKIPIF-- - ---FILE-- -params[0]); -$p = http_parse_params('a=b'); var_dump($p->params[0]); -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -object(stdClass)%a { - ["params"]=> - array(2) { - [0]=> - string(9) "text/html" - [1]=> - array(1) { - ["charset"]=> - string(10) "iso-8859-1" - } - } -} -object(stdClass)%a { - ["params"]=> - array(2) { - [0]=> - string(9) "text/html" - [1]=> - array(1) { - ["charset"]=> - string(10) "iso-8859-1" - } - } -} -object(stdClass)%a { - ["params"]=> - array(2) { - [0]=> - string(10) "attachment" - [1]=> - array(1) { - ["filename"]=> - string(13) "gol;got,a.ext" - } - } -} -object(stdClass)%a { - ["params"]=> - array(3) { - [0]=> - string(6) "public" - [1]=> - string(15) "must-revalidate" - [2]=> - array(1) { - ["max-age"]=> - string(1) "0" - } - } -} -string(1) "a" -array(1) { - ["a"]=> - string(1) "b" -} -Done diff --git a/tests/persistent_handles_001.phpt b/tests/persistent_handles_001.phpt deleted file mode 100644 index 05d63b5..0000000 --- a/tests/persistent_handles_001.phpt +++ /dev/null @@ -1,91 +0,0 @@ ---TEST-- -persistent handles ---SKIPIF-- - ---INI-- -http.persistent.handles.limit=-1 -http.persistent.handles.ident=GLOBAL ---FILE-- - $idents) { - foreach ((array)$idents as $ident => $counts) { - if (!empty($counts["free"])) { - printf("%a, %a, %a\n", $provider, $ident, $counts["free"]); - } - } -} - -http_get("http://www.google.com/", null, $info[]); - -echo "One free request handle within GLOBAL: "; -var_dump(http_persistent_handles_count()->http_request["GLOBAL"]["free"]); - -echo "Reusing request handle: "; -http_get("http://www.google.com/", null, $info[]); -var_dump($info[0]["pretransfer_time"] > 10 * $info[1]["pretransfer_time"], $info[0]["pretransfer_time"], $info[1]["pretransfer_time"]); - -echo "Handles' been cleaned up:\n"; -http_persistent_handles_clean(); -print_r(http_persistent_handles_count()); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -No free handles! -One free request handle within GLOBAL: int(1) -Reusing request handle: bool(true) -float(%f) -float(%f) -Handles' been cleaned up: -stdClass Object -( - [http_request] => Array - ( - [GLOBAL] => Array - ( - [used] => 0 - [free] => 0 - ) - - ) - - [http_request_datashare] => Array - ( - [GLOBAL] => Array - ( - [used] => 0 - [free] => 0 - ) - - ) - - [http_request_datashare_lock] => Array - ( - [GLOBAL] => Array - ( - [used] => 0 - [free] => 0 - ) - - ) - - [http_request_pool] => Array - ( - [GLOBAL] => Array - ( - [used] => 0 - [free] => 0 - ) - - ) - -) -Done diff --git a/tests/persistent_handles_002.phpt b/tests/persistent_handles_002.phpt deleted file mode 100644 index 5b5d28c..0000000 --- a/tests/persistent_handles_002.phpt +++ /dev/null @@ -1,83 +0,0 @@ ---TEST-- -persistent handles ---SKIPIF-- - ---INI-- -http.persistent.handles.limit=-1 -http.persistent.handles.ident=GLOBAL ---FILE-- - $idents) { - foreach ((array)$idents as $ident => $counts) { - if (!empty($counts["free"])) { - printf("%a, %a, %a\n", $provider, $ident, $counts["free"]); - } - } -} - -http_get("http://www.google.com/", null, $info[]); - -echo "One free request handle within GLOBAL: "; -$h = http_persistent_handles_count(); -var_dump($h->http_request["GLOBAL"]["free"]); - -echo "Reusing request handle: "; -http_get("http://www.google.com/", null, $info[]); -var_dump($info[0]["pretransfer_time"] > 10 * $info[1]["pretransfer_time"], $info[0]["pretransfer_time"], $info[1]["pretransfer_time"]); - -echo "Handles' been cleaned up:\n"; -http_persistent_handles_clean(); -print_r(http_persistent_handles_count()); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -No free handles! -One free request handle within GLOBAL: int(1) -Reusing request handle: bool(true) -float(%f) -float(%f) -Handles' been cleaned up: -stdClass Object -( - [http_request] => Array - ( - [GLOBAL] => Array - ( - [used] => 0 - [free] => 0 - ) - - ) - - [http_request_datashare] => Array - ( - [GLOBAL] => Array - ( - [used] => 0 - [free] => 0 - ) - - ) - - [http_request_pool] => Array - ( - [GLOBAL] => Array - ( - [used] => 0 - [free] => 0 - ) - - ) - -) -Done diff --git a/tests/persistent_handles_003.phpt b/tests/persistent_handles_003.phpt deleted file mode 100644 index f676f56..0000000 --- a/tests/persistent_handles_003.phpt +++ /dev/null @@ -1,62 +0,0 @@ ---TEST-- -persistent handles ---SKIPIF-- - ---INI-- -http.persistent.handles.limit=-1 -http.persistent.handles.ident=GLOBAL ---FILE-- - $idents) { - foreach ((array)$idents as $ident => $counts) { - if (!empty($counts["free"])) { - printf("%a, %a, %a\n", $provider, $ident, $counts["free"]); - } - } -} - -http_get("http://www.google.com/", null, $info[]); - -echo "One free request handle within GLOBAL: "; -$h = http_persistent_handles_count(); -var_dump($h->http_request["GLOBAL"]["free"]); - -echo "Reusing request handle: "; -http_get("http://www.google.com/", null, $info[]); -var_dump($info[0]["pretransfer_time"] > 10 * $info[1]["pretransfer_time"], $info[0]["pretransfer_time"], $info[1]["pretransfer_time"]); - -echo "Handles' been cleaned up:\n"; -http_persistent_handles_clean(); -print_r(http_persistent_handles_count()); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -No free handles! -One free request handle within GLOBAL: int(1) -Reusing request handle: bool(true) -float(%f) -float(%f) -Handles' been cleaned up: -stdClass Object -( - [http_request] => Array - ( - [GLOBAL] => Array - ( - [used] => 0 - [free] => 0 - ) - - ) - -) -Done diff --git a/tests/phpunit.phpt b/tests/phpunit.phpt new file mode 100644 index 0000000..087923e --- /dev/null +++ b/tests/phpunit.phpt @@ -0,0 +1,24 @@ +--TEST-- +unit tests +--SKIPIF-- + +--INI-- +date.timezone=Europe/Vienna +--FILE-- +run(array("--process-isolation", __DIR__."/../phpunit/")); +?> +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann. + +%a + +Time: %s, Memory: %s + +OK (%d tests, %d assertions) + diff --git a/tests/propertyproxy001.phpt b/tests/propertyproxy001.phpt new file mode 100644 index 0000000..da17577 --- /dev/null +++ b/tests/propertyproxy001.phpt @@ -0,0 +1,92 @@ +--TEST-- +property proxy +--FILE-- +headers["bykey"] = 1; + var_dump($this->headers); + + $h = &$this->headers; + $h["by1ref"] = 2; + var_dump($this->headers); + + $x = &$this->headers["byXref"]; + + $h = &$this->headers["by2ref"]; + $h = 1; + var_dump($this->headers); + + $x = 2; + var_dump($this->headers); + + $this->headers["bynext"][] = 1; + $this->headers["bynext"][] = 2; + $this->headers["bynext"][] = 3; + var_dump($this->headers); + } +} + +$m=new m; +$m->test(); +echo $m,"\n"; + +?> +DONE +--EXPECTF-- +array(1) { + ["bykey"]=> + int(1) +} +array(2) { + ["bykey"]=> + int(1) + ["by1ref"]=> + int(2) +} +array(3) { + ["bykey"]=> + int(1) + ["by1ref"]=> + int(2) + ["by2ref"]=> + &int(1) +} +array(4) { + ["bykey"]=> + int(1) + ["by1ref"]=> + int(2) + ["by2ref"]=> + &int(1) + ["byXref"]=> + &int(2) +} +array(5) { + ["bykey"]=> + int(1) + ["by1ref"]=> + int(2) + ["by2ref"]=> + &int(1) + ["byXref"]=> + &int(2) + ["bynext"]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} +bykey: 1 +by1ref: 2 +by2ref: 1 +byXref: 2 +bynext: 1, 2, 3 + +DONE + diff --git a/tests/querystring_001.phpt b/tests/querystring_001.phpt new file mode 100644 index 0000000..203be33 --- /dev/null +++ b/tests/querystring_001.phpt @@ -0,0 +1,179 @@ +--TEST-- +query string +--SKIPIF-- + +--GET-- +str=abc&num=-123&dec=123.123&bool=1&arr[]=1&arr[]=2&ma[l1][l2]=2&ma[l2][l3][l4]=3 +--FILE-- +getString("str")); +var_dump($q->getInt("num")); +var_dump($q->getFloat("dec")); +var_dump($q->getInt("dec")); +var_dump($q->getFloat("dec")); +var_dump($q->getBool("bool")); +var_dump($q->getInt("bool")); +var_dump($q->getBool("num")); +var_dump($q->getInt("num")); +var_dump($q->getArray("arr")); +var_dump($q->getArray("ma")); +var_dump($q->getObject("arr")); +var_dump($q->getObject("ma")); + +$s = $q->toString(); + +printf("\nClone modifications do not alter global instance:\n"); +$q->mod(array("arr" => array(3 => 3))); +printf("%s\n", $q); + +printf("\nClone modifications do not alter standard instance:\n"); +$q2 = new http\QueryString($s); +$q3 = $q2->mod(array("arr" => array(3 => 3))); +printf("%s\n%s\n", $q2, $q3); +#var_dump($q2, $q3); + +printf("\nIterator:\n"); +$it = new RecursiveIteratorIterator($q2, RecursiveIteratorIterator::SELF_FIRST); +foreach ($it as $k => $v) { + $i = $it->getDepth()*8; + @printf("%{$i}s: %s\n", $k, $v); +} + +printf("\nReplace a multi dimensional key:\n"); +printf("%s\n", $q2->mod(array("ma" => null))->set(array("ma" => array("l1" => false)))); + +printf("\nXlate:\n"); +$qu = new http\QueryString("ü=ö"); +printf("utf8: %s\n", $qu); +printf("latin1: %s\n", method_exists($qu, "xlate") ? $qu->xlate("utf-8", "latin1") : "%FC=%F6"); + +printf("\nOffsets:\n"); +var_dump($q2["ma"]); +$q2["ma"] = array("bye"); +var_dump($q2["ma"]); +var_dump(isset($q2["ma"])); +unset($q2["ma"]); +var_dump(isset($q2["ma"])); + +echo "Done\n"; +?> +--EXPECTF-- +Test + +Global instance: +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 + +Standard getters: +string(3) "abc" +int(-123) +float(123.123) +int(123) +float(123.123) +bool(true) +int(1) +bool(true) +int(-123) +array(2) { + [0]=> + string(1) "1" + [1]=> + string(1) "2" +} +array(2) { + ["l1"]=> + array(1) { + ["l2"]=> + string(1) "2" + } + ["l2"]=> + array(1) { + ["l3"]=> + array(1) { + ["l4"]=> + string(1) "3" + } + } +} +object(stdClass)#%d (2) { + [0]=> + string(1) "1" + [1]=> + string(1) "2" +} +object(stdClass)#%d (2) { + ["l1"]=> + array(1) { + ["l2"]=> + string(1) "2" + } + ["l2"]=> + array(1) { + ["l3"]=> + array(1) { + ["l4"]=> + string(1) "3" + } + } +} + +Clone modifications do not alter global instance: +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 + +Clone modifications do not alter standard instance: +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&arr%5B3%5D=3&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 + +Iterator: +str: abc +num: -123 +dec: 123.123 +bool: 1 +arr: Array + 0: 1 + 1: 2 +ma: Array + l1: Array + l2: 2 + l2: Array + l3: Array + l4: 3 + +Replace a multi dimensional key: +str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D= + +Xlate: +utf8: %C3%BC=%C3%B6 +latin1: %FC=%F6 + +Offsets: +array(2) { + ["l1"]=> + array(1) { + ["l2"]=> + string(1) "2" + } + ["l2"]=> + array(1) { + ["l3"]=> + array(1) { + ["l4"]=> + string(1) "3" + } + } +} +array(1) { + [0]=> + string(3) "bye" +} +bool(true) +bool(false) +Done diff --git a/tests/redirect_011.phpt b/tests/redirect_011.phpt deleted file mode 100644 index 70a0262..0000000 --- a/tests/redirect_011.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -http_redirect() with params ---SKIPIF-- - ---ENV-- -HTTP_HOST=localhost ---FILE-- - 1, 'b' => 2)); -?> ---EXPECTF-- -Status: 302%s -X-Powered-By: PHP/%a -Location: http://localhost/redirect?a=1&b=2 -Content-type: %a - -Redirecting to http://localhost/redirect?a=1&b=2. - diff --git a/tests/redirect_011_logging.phpt b/tests/redirect_011_logging.phpt deleted file mode 100644 index 2735172..0000000 --- a/tests/redirect_011_logging.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -logging redirects ---SKIPIF-- - ---ENV-- -HTTP_HOST=example.com ---FILE-- - ---EXPECTF-- -%aTEST -%d%d%d%d-%d%d-%d%d %d%d:%d%d:%d%d [302-REDIRECT] Location: http%a <%a> -Done diff --git a/tests/redirect_012.phpt b/tests/redirect_012.phpt deleted file mode 100644 index 977b593..0000000 --- a/tests/redirect_012.phpt +++ /dev/null @@ -1,27 +0,0 @@ ---TEST-- -http_redirect() with session ---SKIPIF-- - ---ENV-- -HTTP_HOST=localhost ---FILE-- - 1), true); -?> ---EXPECTF-- -Status: 302%s -X-Powered-By: PHP/%a -Set-Cookie: PHPSESSID=%a; path=/ -Expires: %a -Cache-Control: %a -Pragma: %a -Location: http://localhost/redirect?a=1&PHPSESSID=%a -Content-type: %a diff --git a/tests/redirect_012_logging.phpt b/tests/redirect_012_logging.phpt deleted file mode 100644 index bacac45..0000000 --- a/tests/redirect_012_logging.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -logging redirects ---SKIPIF-- - ---ENV-- -HTTP_HOST=example.com ---FILE-- - ---EXPECTF-- -%aTEST -%d%d%d%d-%d%d-%d%d %d%d:%d%d:%d%d [302-REDIRECT] Location: http%a <%a> -Done diff --git a/tests/redirect_013.phpt b/tests/redirect_013.phpt deleted file mode 100644 index fb14140..0000000 --- a/tests/redirect_013.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -http_redirect() permanent ---SKIPIF-- - ---ENV-- -HTTP_HOST=localhost ---FILE-- - ---EXPECTF-- -Status: 301%s -X-Powered-By: PHP/%a -Location: http://localhost/redirect -Content-type: %a - -Redirecting to http://localhost/redirect. - diff --git a/tests/redirect_013_logging.phpt b/tests/redirect_013_logging.phpt deleted file mode 100644 index b2623bf..0000000 --- a/tests/redirect_013_logging.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -logging redirects ---SKIPIF-- - ---ENV-- -HTTP_HOST=example.com ---FILE-- - ---EXPECTF-- -%aTEST -%d%d%d%d-%d%d-%d%d %d%d:%d%d:%d%d [301-REDIRECT] Location: http%a <%a> -Done diff --git a/tests/request_cookies.phpt b/tests/request_cookies.phpt deleted file mode 100644 index f83f46a..0000000 --- a/tests/request_cookies.phpt +++ /dev/null @@ -1,52 +0,0 @@ ---TEST-- -urlencoded cookies ---SKIPIF-- - ---FILE-- - "val=ue"); - -$r = new HttpRequest("http://dev.iworks.at/ext-http/.print_request.php", HTTP_METH_GET, array("cookies" => $cookies)); -$r->recordHistory = true; -$r->send(); -$r->setOptions(array('encodecookies' => false)); -$r->send(); -echo $r->getHistory()->toString(true); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -GET /ext-http/.print_request.php HTTP/1.1 -User-Agent: %a -Host: dev.iworks.at -Accept: */* -Cookie: name=val%3Due -HTTP/1.1 200 OK -%a - -Array -( - [name] => val=ue -) - -GET /ext-http/.print_request.php HTTP/1.1 -User-Agent: %a -Host: dev.iworks.at -Accept: */* -Cookie: name=val=ue; -HTTP/1.1 200 OK -%a - -Array -( - [name] => val=ue -) - -Done diff --git a/tests/request_etag.phpt b/tests/request_etag.phpt deleted file mode 100644 index 9201b4b..0000000 --- a/tests/request_etag.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -request etag ---SKIPIF-- - ---FILE-- - '"26ad3a-5-95eb19c0"'))); -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -string(%d) "HTTP/1.1 304 Not Modified -Date: %a -Server: %a -ETag: "26ad3a-5-95eb19c0" -" -Done \ No newline at end of file diff --git a/tests/request_gzip.phpt b/tests/request_gzip.phpt deleted file mode 100644 index 3c5ae6f..0000000 --- a/tests/request_gzip.phpt +++ /dev/null @@ -1,53 +0,0 @@ ---TEST-- -GZIP request ---SKIPIF-- - ---FILE-- - true)))); - -echo "Done\n"; ---EXPECTF-- -%aTEST -object(stdClass)%a { - ["type"]=> - int(2) - ["httpVersion"]=> - float(1.1) - ["responseCode"]=> - int(200) - ["responseStatus"]=> - string(2) "OK" - ["headers"]=> - array(%d) { - %a - ["Vary"]=> - string(15) "Accept-Encoding" - ["Content-Type"]=> - string(9) "text/html" - ["X-Original-Transfer-Encoding"]=> - string(7) "chunked" - ["Content-Length"]=> - string(2) "26" - ["X-Original-Content-Encoding"]=> - string(4) "gzip" - ["X-Original-Content-Length"]=> - string(2) "51" - } - ["body"]=> - string(26) "Array -( - [gzip] => 1 -) -" - ["parentMessage"]=> - NULL -} -Done - diff --git a/tests/request_methods.phpt b/tests/request_methods.phpt deleted file mode 100644 index 05f6b07..0000000 --- a/tests/request_methods.phpt +++ /dev/null @@ -1,144 +0,0 @@ ---TEST-- -request methods ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -int(0) -UNKNOWN -int(0) -int(1) -GET -int(1) -int(2) -HEAD -int(2) -int(3) -POST -int(3) -int(4) -PUT -int(4) -int(5) -DELETE -int(5) -int(6) -OPTIONS -int(6) -int(7) -TRACE -int(7) -int(8) -CONNECT -int(8) -int(9) -PROPFIND -int(9) -int(10) -PROPPATCH -int(10) -int(11) -MKCOL -int(11) -int(12) -COPY -int(12) -int(13) -MOVE -int(13) -int(14) -LOCK -int(14) -int(15) -UNLOCK -int(15) -int(16) -VERSION-CONTROL -int(16) -int(17) -REPORT -int(17) -int(18) -CHECKOUT -int(18) -int(19) -CHECKIN -int(19) -int(20) -UNCHECKOUT -int(20) -int(21) -MKWORKSPACE -int(21) -int(22) -UPDATE -int(22) -int(23) -LABEL -int(23) -int(24) -MERGE -int(24) -int(25) -BASELINE-CONTROL -int(25) -int(26) -MKACTIVITY -int(26) -int(27) -ACL -int(27) -int(0) -UNKNOWN -int(0) -int(28) -int(28) -int(29) -int(29) -int(30) -int(30) -int(31) -int(31) -int(32) -int(32) -bool(true) -int(0) -int(0) -bool(true) -int(0) -int(0) -bool(true) -int(0) -int(0) -bool(true) -int(0) -int(0) -bool(true) -int(0) -int(0) -Done diff --git a/tests/request_put_data.phpt b/tests/request_put_data.phpt deleted file mode 100644 index a2887fd..0000000 --- a/tests/request_put_data.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -http_put_data() ---SKIPIF-- - ---FILE-- - CURLBUF_SIZE */); -$resp = http_put_data("http://dev.iworks.at/ext-http/.print_put.php5", $data); -$mess = http_parse_message($resp); -var_dump($data === $mess->body); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -bool(true) -Done diff --git a/tests/send_data_001.phpt b/tests/send_data_001.phpt deleted file mode 100644 index d744d8d..0000000 --- a/tests/send_data_001.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -http_send_data() NIL-NUM range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=-5 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Content-Type: text/plain -Accept-Ranges: bytes -Content-Range: bytes 5995-5999/6000 -Content-Length: 5 - -23abc diff --git a/tests/send_data_002.phpt b/tests/send_data_002.phpt deleted file mode 100644 index 1dc775b..0000000 --- a/tests/send_data_002.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -http_send_data() NUM-NUM range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=5-6 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Content-Type: text/plain -Accept-Ranges: bytes -Content-Range: bytes 5-6/6000 -Content-Length: 2 - -c1 diff --git a/tests/send_data_003.phpt b/tests/send_data_003.phpt deleted file mode 100644 index f47c38d..0000000 --- a/tests/send_data_003.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -http_send_data() NUM-NIL range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=5981- ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Content-Type: text/plain -Accept-Ranges: bytes -Content-Range: bytes 5981-5999/6000 -Content-Length: 19 - -c123abc123abc123abc diff --git a/tests/send_data_004.phpt b/tests/send_data_004.phpt deleted file mode 100644 index 12223fd..0000000 --- a/tests/send_data_004.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -http_send_data() syntactically invalid range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=123,-wtf ? ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%s -Content-Type: text/plain -Accept-Ranges: bytes -Content-Length: 6000 - -123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc \ No newline at end of file diff --git a/tests/send_data_005.phpt b/tests/send_data_005.phpt deleted file mode 100644 index c373b10..0000000 --- a/tests/send_data_005.phpt +++ /dev/null @@ -1,17 +0,0 @@ ---TEST-- -http_send_data() oversized range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=5990-6000 ---FILE-- - ---EXPECTF-- -Status: 416%a \ No newline at end of file diff --git a/tests/send_data_006.phpt b/tests/send_data_006.phpt deleted file mode 100644 index 418d4f0..0000000 --- a/tests/send_data_006.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -http_send_data() multiple ranges ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=0-3, 4-5,9-11 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Type: multipart/byteranges; boundary=%d.%d - - ---%d.%d -Content-Type: text/plain -Content-Range: bytes 0-3/6000 - -123a ---%d.%d -Content-Type: text/plain -Content-Range: bytes 4-5/6000 - -bc ---%d.%d -Content-Type: text/plain -Content-Range: bytes 9-11/6000 - -abc ---%d.%d-- diff --git a/tests/send_data_007.phpt b/tests/send_data_007.phpt deleted file mode 100644 index e82fa83..0000000 --- a/tests/send_data_007.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -http_send_data() NIL-NIL range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=0-0 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Content-Type: text/plain -Accept-Ranges: bytes -Content-Range: bytes 0-0/3 -Content-Length: 1 - -a diff --git a/tests/send_data_008.phpt b/tests/send_data_008.phpt deleted file mode 100644 index 3a69563..0000000 --- a/tests/send_data_008.phpt +++ /dev/null @@ -1,33 +0,0 @@ ---TEST-- -http_send_data() multiple ranges ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=0-0,-1 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Type: multipart/byteranges; boundary=%d.%d - - ---%d.%d -Content-Type: text/plain -Content-Range: bytes 0-0/2 - -0 ---%d.%d -Content-Type: text/plain -Content-Range: bytes 1-1/2 - -1 ---%d.%d-- diff --git a/tests/send_data_010.phpt b/tests/send_data_010.phpt deleted file mode 100644 index 9553c8d..0000000 --- a/tests/send_data_010.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -http_send_data() HTTP_SENDBUF_SIZE long string ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Length: 20 -Content-type: %s - -00000000000000000000 diff --git a/tests/send_data_011.phpt b/tests/send_data_011.phpt deleted file mode 100644 index 9506078..0000000 --- a/tests/send_data_011.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -http_send_data() last modified caching ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%s -Cache-Control: private, must-revalidate, max-age=0 -Last-Modified: %s, %d %s %d %d:%d:%d GMT -Accept-Ranges: bytes -Content-Length: 4 -Content-type: %s - -abc diff --git a/tests/send_failed_precond_001.phpt b/tests/send_failed_precond_001.phpt deleted file mode 100644 index c8dc1c8..0000000 --- a/tests/send_failed_precond_001.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -http_send() failed precondition ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=0-1 -HTTP_IF_UNMODIFIED_SINCE=Thu, 01 Jan 1970 00:16:40 GMT ---FILE-- - ---EXPECTF-- -Status: 412%s -X-Powered-By: %s -Cache-Control: private, must-revalidate, max-age=0 -Last-Modified: %s -Accept-Ranges: bytes -Content-type: text/html diff --git a/tests/send_file_005.phpt b/tests/send_file_005.phpt deleted file mode 100644 index 51f6b8f..0000000 --- a/tests/send_file_005.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -http_send_file() multiple ranges ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=0-3, 4-5,9-11 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Type: multipart/byteranges; boundary=%d.%d - - ---%d.%d -Content-Type: text/plain -Content-Range: bytes 0-3/1010 - -0123 ---%d.%d -Content-Type: text/plain -Content-Range: bytes 4-5/1010 - -45 ---%d.%d -Content-Type: text/plain -Content-Range: bytes 9-11/1010 - -901 ---%d.%d-- diff --git a/tests/send_file_006.phpt b/tests/send_file_006.phpt deleted file mode 100644 index 1b93319..0000000 --- a/tests/send_file_006.phpt +++ /dev/null @@ -1,34 +0,0 @@ ---TEST-- -http_send_file() first/last byte range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=0-0,-1 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Type: multipart/byteranges; boundary=%d.%d - - ---%d.%d -Content-Type: text/plain -Content-Range: bytes 0-0/1010 - -0 ---%d.%d -Content-Type: text/plain -Content-Range: bytes 1009-1009/1010 - - - ---%d.%d-- diff --git a/tests/send_file_007.phpt b/tests/send_file_007.phpt deleted file mode 100644 index 09f1167..0000000 --- a/tests/send_file_007.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -http_send_file() NIL-NIL range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=0-0 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Range: bytes 0-0/1010 -Content-Length: 1 -Content-type: %s - -0 diff --git a/tests/send_file_008.phpt b/tests/send_file_008.phpt deleted file mode 100644 index 556cea7..0000000 --- a/tests/send_file_008.phpt +++ /dev/null @@ -1,28 +0,0 @@ ---TEST-- -http_send_file() ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Length: 1010 -Content-type: %s - -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 diff --git a/tests/send_file_009.phpt b/tests/send_file_009.phpt deleted file mode 100644 index 2d360b0..0000000 --- a/tests/send_file_009.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -http_send_file() NUM-NUM range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=5-9 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Range: bytes 5-9/1010 -Content-Length: 5 -Content-type: %s - -56789 diff --git a/tests/send_file_010.phpt b/tests/send_file_010.phpt deleted file mode 100644 index d0f4318..0000000 --- a/tests/send_file_010.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -http_send_file() NIL-NUM range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=-9 ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Range: bytes 1001-1009/1010 -Content-Length: 9 -Content-type: %s - -23456789 diff --git a/tests/send_file_011.phpt b/tests/send_file_011.phpt deleted file mode 100644 index 8444a7d..0000000 --- a/tests/send_file_011.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -http_send_file() NUM-NIL range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=1000- ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Range: bytes 1000-1009/1010 -Content-Length: 10 -Content-type: %s - -123456789 diff --git a/tests/send_file_012.phpt b/tests/send_file_012.phpt deleted file mode 100644 index 0e4ce0e..0000000 --- a/tests/send_file_012.phpt +++ /dev/null @@ -1,30 +0,0 @@ ---TEST-- -http_send_file() syntactically invalid range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=xxx ---FILE-- - ---EXPECTF-- -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-Length: 1010 -Content-type: %s - -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 diff --git a/tests/send_file_013.phpt b/tests/send_file_013.phpt deleted file mode 100644 index cd3f3cb..0000000 --- a/tests/send_file_013.phpt +++ /dev/null @@ -1,19 +0,0 @@ ---TEST-- -http_send_file() oversized range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=-1111 ---FILE-- - ---EXPECTF-- -Status: 416 -X-Powered-By: PHP/%s -Accept-Ranges: bytes -Content-type: %s diff --git a/tests/send_ifrange_001.phpt b/tests/send_ifrange_001.phpt deleted file mode 100644 index 40185ac..0000000 --- a/tests/send_ifrange_001.phpt +++ /dev/null @@ -1,27 +0,0 @@ ---TEST-- -http_send() If-Range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=0-1 -HTTP_IF_RANGE="abc" ---FILE-- - ---EXPECTF-- -Status: 206%s -X-Powered-By: %s -Cache-Control: private, must-revalidate, max-age=0 -ETag: "abc" -Accept-Ranges: bytes -Content-Range: bytes 0-1/%d -Content-Length: 2 -Content-type: text/html - - diff --git a/tests/send_ifrange_003.phpt b/tests/send_ifrange_003.phpt deleted file mode 100644 index 226c72f..0000000 --- a/tests/send_ifrange_003.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -http_send() If-Range ---SKIPIF-- - ---ENV-- -HTTP_RANGE=bytes=0-1 -HTTP_IF_RANGE="abcd" ---FILE-- - ---EXPECTF-- -X-Powered-By: %s -Cache-Control: private, must-revalidate, max-age=0 -ETag: "abc" -Accept-Ranges: bytes -Content-Length: %d -Content-type: text/html - -%a diff --git a/tests/serialize001.phpt b/tests/serialize001.phpt new file mode 100644 index 0000000..411e4a3 --- /dev/null +++ b/tests/serialize001.phpt @@ -0,0 +1,27 @@ +--TEST-- +serialization +--SKIPIF-- + +--FILE-- +getClasses() as $class) { + if ($class->isInstantiable()) { + #printf("%s\n", $class->getName()); + $instance = $class->newInstance(); + $serialized = serialize($instance); + $unserialized = unserialize($serialized); + + foreach (array("toString", "toArray") as $m) { + if ($class->hasMethod($m)) { + #printf("%s#%s\n", $class->getName(), $m); + $unserialized->$m(); + } + } + } +} +?> +DONE +--EXPECTF-- +DONE diff --git a/tests/skip.inc b/tests/skip.inc deleted file mode 100644 index d8770fb..0000000 --- a/tests/skip.inc +++ /dev/null @@ -1,15 +0,0 @@ -= v%s",$ver)); } -function checkmax($ver) { skipif(version_compare(PHP_VERSION, $ver) > 0, sprintf("need PHP <= v%s",$ver)); } -function checkurl($url) { skipif(!@fsockopen($url, 80), "$url not responsive"); } -function checkcls($cls) { skipif(!class_exists($cls), "need class $cls"); } -function checkver($ver) { checkmin($ver); } -checkext('http'); -?> diff --git a/tests/skipif.inc b/tests/skipif.inc new file mode 100644 index 0000000..0f10264 --- /dev/null +++ b/tests/skipif.inc @@ -0,0 +1,3 @@ + ---FILE-- - ---EXPECTF-- -%aTEST -string(30) "5 -Here -2 -we -5 - go! - -0 -" -string(12) "Here we go! -" -Done diff --git a/tests/stream_filters_002.phpt b/tests/stream_filters_002.phpt deleted file mode 100644 index 5167e14..0000000 --- a/tests/stream_filters_002.phpt +++ /dev/null @@ -1,50 +0,0 @@ ---TEST-- -gzip stream filters ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -bool(true) -bool(true) -bool(true) -Done diff --git a/tests/stream_filters_003.phpt b/tests/stream_filters_003.phpt deleted file mode 100644 index 2cf8102..0000000 --- a/tests/stream_filters_003.phpt +++ /dev/null @@ -1,42 +0,0 @@ ---TEST-- -stream filter fun ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%aTEST -This is some stream filter fun; we'll see if it bails out or not. -The text should come out at the other end of the stream exactly like written to it. -Go figure! diff --git a/tests/url001.phpt b/tests/url001.phpt new file mode 100644 index 0000000..cd792f2 --- /dev/null +++ b/tests/url001.phpt @@ -0,0 +1,25 @@ +--TEST-- +url from env +--SKIPIF-- + include "skippif.inc"; ?> +--ENV-- +SERVER_PORT=55555 +HTTP_HOST=example.com +--GET-- +s=b&i=0&e=&a[]=1&a[]=2 +--FILE-- + "https", "port" => 443))); +printf("%s\n", new http\Url(array("path" => "/./up/../down/../././//index.php/.", "query" => null), null, http\Url::SANITIZE_PATH|http\Url::FROM_ENV)); +printf("%s\n", new http\Url(null, null, 0)); +?> +DONE +--EXPECTF-- +http://example.com:55555/?s=b&i=0&e=&a[]=1&a[]=2 +http://example.com:55555/index?s=b&i=0&e=&a[]=1&a[]=2 +https://example.com/?s=b&i=0&e=&a[]=1&a[]=2 +http://example.com:55555/index.php/ +http://localhost/ +DONE diff --git a/tests/version001.phpt b/tests/version001.phpt new file mode 100644 index 0000000..52acba6 --- /dev/null +++ b/tests/version001.phpt @@ -0,0 +1,21 @@ +--TEST-- +version parse error +--SKIPIF-- + +--FILE-- +setHttpVersion("1-1"); + $m->setHttpVersion("one.one"); +} catch (http\Exception $e) { + echo $e->getMessage(),"\n"; +} +?> +--EXPECTF-- +Notice: http\Message::setHttpVersion(): Non-standard version separator '-' in HTTP protocol version '1-1' in %s +http\Message::setHttpVersion(): Could not parse HTTP protocol version 'one.one' + -- 2.30.2