Index: trunk/phase3/maintenance/parserTests.inc |
— | — | @@ -1618,8 +1618,6 @@ |
1619 | 1619 | } |
1620 | 1620 | |
1621 | 1621 | function post( $url, $data ) { |
1622 | | - // @fixme: for whatever reason, I get a 417 fail when using CURL's multipart form submit. |
1623 | | - // If we do form URL encoding ourselves, though, it should work. |
1624 | | - return Http::post( $url, array( 'postdata' => wfArrayToCGI( $data ) ) ); |
| 1622 | + return Http::post( $url, array( 'postData' => $data) ); |
1625 | 1623 | } |
1626 | 1624 | } |
Index: trunk/phase3/tests/HttpTest.php |
— | — | @@ -52,10 +52,10 @@ |
53 | 53 | self::$content["POST $u"] = file_get_contents( $content ); |
54 | 54 | self::$headers["POST $u"] = file_get_contents( $headers ); |
55 | 55 | } |
56 | | - foreach ( $this->test_posturl as $u => $postdata ) { |
57 | | - system( "curl -0 -s -X POST -d '$postdata' -D $headers '$u' -o $content" ); |
58 | | - self::$content["POST $u => $postdata"] = file_get_contents( $content ); |
59 | | - self::$headers["POST $u => $postdata"] = file_get_contents( $headers ); |
| 56 | + foreach ( $this->test_posturl as $u => $postData ) { |
| 57 | + system( "curl -0 -s -X POST -d '$postData' -D $headers '$u' -o $content" ); |
| 58 | + self::$content["POST $u => $postData"] = file_get_contents( $content ); |
| 59 | + self::$headers["POST $u => $postData"] = file_get_contents( $headers ); |
60 | 60 | } |
61 | 61 | unlink( $content ); |
62 | 62 | unlink( $headers ); |
— | — | @@ -138,7 +138,7 @@ |
139 | 139 | $opt['proxy'] = $proxy; |
140 | 140 | } |
141 | 141 | |
142 | | - /* no postdata here because the only request I could find in code so far didn't have any */ |
| 142 | + /* no postData here because the only request I could find in code so far didn't have any */ |
143 | 143 | foreach ( $this->test_requesturl as $u ) { |
144 | 144 | $r = Http::request( "POST", $u, $opt ); |
145 | 145 | $this->assertEquals( self::$content["POST $u"], "$r", "POST $u with $wgHTTPEngine" ); |
— | — | @@ -253,7 +253,7 @@ |
254 | 254 | self::runHTTPGets(); |
255 | 255 | } |
256 | 256 | |
257 | | - /* ./phase3/maintenance/parserTests.inc:1618: return Http::post( $url, array( 'postdata' => wfArrayToCGI( $data ) ) ); */ |
| 257 | + /* ./phase3/maintenance/parserTests.inc:1618: return Http::post( $url, array( 'postData' => wfArrayToCGI( $data ) ) ); */ |
258 | 258 | function runHTTPPosts($proxy=null) { |
259 | 259 | global $wgHTTPEngine; |
260 | 260 | $opt = array(); |
— | — | @@ -262,11 +262,11 @@ |
263 | 263 | $opt['proxy'] = $proxy; |
264 | 264 | } |
265 | 265 | |
266 | | - foreach ( $this->test_posturl as $u => $postdata ) { |
267 | | - $opt['postdata'] = $postdata; |
| 266 | + foreach ( $this->test_posturl as $u => $postData ) { |
| 267 | + $opt['postData'] = $postData; |
268 | 268 | $r = Http::post( $u, $opt ); |
269 | | - $this->assertEquals( self::$content["POST $u => $postdata"], "$r", |
270 | | - "POST $u (postdata=$postdata) with $wgHTTPEngine" ); |
| 269 | + $this->assertEquals( self::$content["POST $u => $postData"], "$r", |
| 270 | + "POST $u (postData=$postData) with $wgHTTPEngine" ); |
271 | 271 | } |
272 | 272 | } |
273 | 273 | |
Index: trunk/phase3/includes/HttpFunctions.php |
— | — | @@ -12,18 +12,18 @@ |
13 | 13 | * Perform an HTTP request |
14 | 14 | * @param $method string HTTP method. Usually GET/POST |
15 | 15 | * @param $url string Full URL to act on |
16 | | - * @param $opts options to pass to HttpRequest object |
| 16 | + * @param $options options to pass to HttpRequest object |
17 | 17 | * @returns mixed (bool)false on failure or a string on success |
18 | 18 | */ |
19 | | - public static function request( $method, $url, $opts = array() ) { |
20 | | - $opts['method'] = strtoupper( $method ); |
21 | | - if ( !array_key_exists( 'timeout', $opts ) ) { |
22 | | - $opts['timeout'] = 'default'; |
| 19 | + public static function request( $method, $url, $options = array() ) { |
| 20 | + $options['method'] = strtoupper( $method ); |
| 21 | + if ( !isset( $options['timeout'] ) ) { |
| 22 | + $options['timeout'] = 'default'; |
23 | 23 | } |
24 | | - $req = HttpRequest::factory( $url, $opts ); |
| 24 | + $req = HttpRequest::factory( $url, $options ); |
25 | 25 | $status = $req->execute(); |
26 | 26 | if ( $status->isOK() ) { |
27 | | - return $req; |
| 27 | + return $req->getContent(); |
28 | 28 | } else { |
29 | 29 | return false; |
30 | 30 | } |
— | — | @@ -33,17 +33,17 @@ |
34 | 34 | * Simple wrapper for Http::request( 'GET' ) |
35 | 35 | * @see Http::request() |
36 | 36 | */ |
37 | | - public static function get( $url, $timeout = 'default', $opts = array() ) { |
38 | | - $opts['timeout'] = $timeout; |
39 | | - return Http::request( 'GET', $url, $opts ); |
| 37 | + public static function get( $url, $timeout = 'default', $options = array() ) { |
| 38 | + $options['timeout'] = $timeout; |
| 39 | + return Http::request( 'GET', $url, $options ); |
40 | 40 | } |
41 | 41 | |
42 | 42 | /** |
43 | 43 | * Simple wrapper for Http::request( 'POST' ) |
44 | 44 | * @see Http::request() |
45 | 45 | */ |
46 | | - public static function post( $url, $opts = array() ) { |
47 | | - return Http::request( 'POST', $url, $opts ); |
| 46 | + public static function post( $url, $options = array() ) { |
| 47 | + return Http::request( 'POST', $url, $options ); |
48 | 48 | } |
49 | 49 | |
50 | 50 | /** |
— | — | @@ -111,14 +111,16 @@ |
112 | 112 | protected $content; |
113 | 113 | protected $timeout = 'default'; |
114 | 114 | protected $headersOnly = null; |
115 | | - protected $postdata = null; |
| 115 | + protected $postData = null; |
116 | 116 | protected $proxy = null; |
117 | | - protected $no_proxy = false; |
| 117 | + protected $noProxy = false; |
118 | 118 | protected $sslVerifyHost = true; |
119 | 119 | protected $caInfo = null; |
120 | 120 | protected $method = "GET"; |
| 121 | + protected $reqHeaders = array(); |
121 | 122 | protected $url; |
122 | | - protected $parsed_url; |
| 123 | + protected $parsedUrl; |
| 124 | + protected $callback; |
123 | 125 | public $status; |
124 | 126 | |
125 | 127 | /** |
— | — | @@ -129,295 +131,304 @@ |
130 | 132 | * timeout |
131 | 133 | * targetFilePath |
132 | 134 | * requestKey |
133 | | - * headersOnly |
134 | | - * postdata |
| 135 | + * postData |
135 | 136 | * proxy |
136 | | - * no_proxy |
| 137 | + * noProxy |
137 | 138 | * sslVerifyHost |
138 | 139 | * caInfo |
139 | 140 | */ |
140 | | - function __construct( $url = null, $opt = array() ) { |
141 | | - global $wgHTTPTimeout, $wgTitle; |
| 141 | + function __construct( $url, $options = array() ) { |
| 142 | + global $wgHTTPTimeout; |
142 | 143 | |
143 | 144 | $this->url = $url; |
144 | | - $this->parsed_url = parse_url( $url ); |
| 145 | + $this->parsedUrl = parse_url( $url ); |
145 | 146 | |
146 | | - if ( !ini_get( 'allow_url_fopen' ) ) { |
147 | | - throw new MWException( 'allow_url_fopen needs to be enabled for http requests to work' ); |
148 | | - } elseif ( !Http::isValidURI( $this->url ) ) { |
149 | | - throw new MWException( 'Invalid URL' ); |
| 147 | + if ( !Http::isValidURI( $this->url ) ) { |
| 148 | + $this->status = Status::newFromFatal('http-invalid-url'); |
150 | 149 | } else { |
151 | 150 | $this->status = Status::newGood( 100 ); // continue |
152 | 151 | } |
153 | 152 | |
154 | | - if ( array_key_exists( 'timeout', $opt ) && $opt['timeout'] != 'default' ) { |
155 | | - $this->timeout = $opt['timeout']; |
| 153 | + if ( isset($options['timeout']) && $options['timeout'] != 'default' ) { |
| 154 | + $this->timeout = $options['timeout']; |
156 | 155 | } else { |
157 | 156 | $this->timeout = $wgHTTPTimeout; |
158 | 157 | } |
159 | 158 | |
160 | | - $members = array( "targetFilePath", "requestKey", "headersOnly", "postdata", |
161 | | - "proxy", "no_proxy", "sslVerifyHost", "caInfo", "method" ); |
| 159 | + $members = array( "targetFilePath", "requestKey", "postData", |
| 160 | + "proxy", "noProxy", "sslVerifyHost", "caInfo", "method" ); |
162 | 161 | foreach ( $members as $o ) { |
163 | | - if ( array_key_exists( $o, $opt ) ) { |
164 | | - $this->$o = $opt[$o]; |
| 162 | + if ( isset($options[$o]) ) { |
| 163 | + $this->$o = $options[$o]; |
165 | 164 | } |
166 | 165 | } |
167 | | - |
168 | | - if ( is_array( $this->postdata ) ) { |
169 | | - $this->postdata = wfArrayToCGI( $this->postdata ); |
170 | | - } |
171 | | - |
172 | | - $this->initRequest(); |
173 | | - |
174 | | - if ( !$this->no_proxy ) { |
175 | | - $this->proxySetup(); |
176 | | - } |
177 | | - |
178 | | - # Set the referer to $wgTitle, even in command-line mode |
179 | | - # This is useful for interwiki transclusion, where the foreign |
180 | | - # server wants to know what the referring page is. |
181 | | - # $_SERVER['REQUEST_URI'] gives a less reliable indication of the |
182 | | - # referring page. |
183 | | - if ( is_object( $wgTitle ) ) { |
184 | | - $this->setReferrer( $wgTitle->getFullURL() ); |
185 | | - } |
186 | 166 | } |
187 | 167 | |
188 | 168 | /** |
189 | | - * For backwards compatibility, we provide a __toString method so |
190 | | - * that any code that expects a string result from Http::Get() |
191 | | - * will see the content of the request. |
192 | | - */ |
193 | | - function __toString() { |
194 | | - return $this->content; |
195 | | - } |
196 | | - |
197 | | - /** |
198 | 169 | * Generate a new request object |
199 | 170 | * @see HttpRequest::__construct |
200 | 171 | */ |
201 | | - public static function factory( $url, $opt ) { |
| 172 | + public static function factory( $url, $options ) { |
202 | 173 | global $wgHTTPEngine; |
203 | 174 | $engine = $wgHTTPEngine; |
204 | 175 | |
205 | 176 | if ( !$wgHTTPEngine ) { |
206 | 177 | $wgHTTPEngine = function_exists( 'curl_init' ) ? 'curl' : 'php'; |
207 | 178 | } elseif ( $wgHTTPEngine == 'curl' && !function_exists( 'curl_init' ) ) { |
208 | | - throw new MWException( 'FIXME' ); |
| 179 | + throw new MWException( __METHOD__.': curl (http://php.net/curl) is not installed, but $wgHTTPEngine is set to "curl"' ); |
209 | 180 | } |
210 | 181 | |
211 | 182 | switch( $wgHTTPEngine ) { |
212 | 183 | case 'curl': |
213 | | - return new CurlHttpRequest( $url, $opt ); |
| 184 | + return new CurlHttpRequest( $url, $options ); |
214 | 185 | case 'php': |
215 | | - return new PhpHttpRequest( $url, $opt ); |
| 186 | + if ( !wfIniGetBool( 'allow_url_fopen' ) ) { |
| 187 | + throw new MWException( __METHOD__.': allow_url_fopen needs to be enabled for pure PHP http requests to work. '. |
| 188 | + 'If possible, curl should be used instead. See http://php.net/curl.' ); |
| 189 | + } |
| 190 | + return new PhpHttpRequest( $url, $options ); |
216 | 191 | default: |
217 | | - throw new MWException( 'The setting of $wgHTTPEngine is not valid.' ); |
| 192 | + throw new MWException( __METHOD__.': The setting of $wgHTTPEngine is not valid.' ); |
218 | 193 | } |
219 | 194 | } |
220 | 195 | |
| 196 | + /** |
| 197 | + * Get the body, or content, of the response to the request |
| 198 | + * @return string |
| 199 | + */ |
221 | 200 | public function getContent() { |
222 | 201 | return $this->content; |
223 | 202 | } |
224 | 203 | |
225 | | - public function initRequest() { } |
226 | | - public function proxySetup() { } |
227 | | - public function setReferrer( $url ) { } |
228 | | - public function setCallback( $cb ) { } |
229 | | - public function read( $fh, $content ) { } |
230 | | - public function getCode() { } |
231 | | - public function execute() { } |
232 | | -} |
| 204 | + /** |
| 205 | + * Take care of setting up the proxy |
| 206 | + * (override in subclass) |
| 207 | + * @return string |
| 208 | + */ |
| 209 | + public function proxySetup() { |
| 210 | + global $wgHTTPProxy; |
233 | 211 | |
234 | | -/** |
235 | | - * HttpRequest implemented using internal curl compiled into PHP |
236 | | - */ |
237 | | -class CurlHttpRequest extends HttpRequest { |
238 | | - protected $curlHandle; |
239 | | - protected $curlCBSet; |
240 | 212 | |
241 | | - public function initRequest() { |
242 | | - $this->curlHandle = curl_init( $this->url ); |
| 213 | + if ( $this->proxy ) { |
| 214 | + return; |
| 215 | + } |
| 216 | + if ( Http::isLocalURL( $this->url ) ) { |
| 217 | + $this->proxy = 'http://localhost:80/'; |
| 218 | + } elseif ( $wgHTTPProxy ) { |
| 219 | + $this->proxy = $wgHTTPProxy ; |
| 220 | + } |
243 | 221 | } |
244 | 222 | |
245 | | - public function proxySetup() { |
246 | | - global $wgHTTPProxy; |
| 223 | + /** |
| 224 | + * Set the refererer header |
| 225 | + */ |
| 226 | + public function setReferer( $url ) { |
| 227 | + $this->setHeader('Referer', $url); |
| 228 | + } |
247 | 229 | |
248 | | - if ( is_string( $this->proxy ) ) { |
249 | | - curl_setopt( $this->curlHandle, CURLOPT_PROXY, $this->proxy ); |
250 | | - } else if ( Http::isLocalURL( $this->url ) ) { /* Not sure this makes any sense. */ |
251 | | - curl_setopt( $this->curlHandle, CURLOPT_PROXY, 'localhost:80' ); |
252 | | - } else if ( $wgHTTPProxy ) { |
253 | | - curl_setopt( $this->curlHandle, CURLOPT_PROXY, $wgHTTPProxy ); |
| 230 | + /** |
| 231 | + * Set the user agent |
| 232 | + */ |
| 233 | + public function setUserAgent( $UA ) { |
| 234 | + $this->setHeader('User-Agent', $UA); |
| 235 | + } |
| 236 | + |
| 237 | + /** |
| 238 | + * Set an arbitrary header |
| 239 | + */ |
| 240 | + public function setHeader($name, $value) { |
| 241 | + // I feel like I should normalize the case here... |
| 242 | + $this->reqHeaders[$name] = $value; |
| 243 | + } |
| 244 | + |
| 245 | + /** |
| 246 | + * Get an array of the headers |
| 247 | + */ |
| 248 | + public function getHeaderList() { |
| 249 | + $list = array(); |
| 250 | + |
| 251 | + foreach($this->reqHeaders as $name => $value) { |
| 252 | + $list[] = "$name: $value"; |
254 | 253 | } |
| 254 | + return $list; |
255 | 255 | } |
256 | 256 | |
257 | | - public function setCallback( $cb ) { |
258 | | - if ( !$this->curlCBSet ) { |
259 | | - $this->curlCBSet = true; |
260 | | - curl_setopt( $this->curlHandle, CURLOPT_WRITEFUNCTION, $cb ); |
| 257 | + /** |
| 258 | + * Set the callback |
| 259 | + * @param $callback callback |
| 260 | + */ |
| 261 | + public function setCallback( $callback ) { |
| 262 | + $this->callback = $callback; |
| 263 | + } |
| 264 | + |
| 265 | + /** |
| 266 | + * A generic callback to read in the response from a remote server |
| 267 | + * @param $fh handle |
| 268 | + * @param $content string |
| 269 | + */ |
| 270 | + public function read( $fh, $content ) { |
| 271 | + $this->content .= $content; |
| 272 | + return strlen( $content ); |
| 273 | + } |
| 274 | + |
| 275 | + /** |
| 276 | + * Take care of whatever is necessary to perform the URI request. |
| 277 | + * @return Status |
| 278 | + */ |
| 279 | + public function execute() { |
| 280 | + global $wgTitle; |
| 281 | + |
| 282 | + if( strtoupper($this->method) == "HEAD" ) { |
| 283 | + $this->headersOnly = true; |
261 | 284 | } |
| 285 | + |
| 286 | + if ( is_array( $this->postData ) ) { |
| 287 | + $this->postData = wfArrayToCGI( $this->postData ); |
| 288 | + } |
| 289 | + |
| 290 | + if ( is_object( $wgTitle ) && !isset($this->reqHeaders['Referer']) ) { |
| 291 | + $this->setReferer( $wgTitle->getFullURL() ); |
| 292 | + } |
| 293 | + |
| 294 | + if ( !$this->noProxy ) { |
| 295 | + $this->proxySetup(); |
| 296 | + } |
| 297 | + |
| 298 | + if ( !$this->callback ) { |
| 299 | + $this->setCallback( array( $this, 'read' ) ); |
| 300 | + } |
| 301 | + |
| 302 | + if ( !isset($this->reqHeaders['User-Agent']) ) { |
| 303 | + $this->setUserAgent(Http::userAgent()); |
| 304 | + } |
262 | 305 | } |
| 306 | +} |
263 | 307 | |
| 308 | +/** |
| 309 | + * HttpRequest implemented using internal curl compiled into PHP |
| 310 | + */ |
| 311 | +class CurlHttpRequest extends HttpRequest { |
| 312 | + protected $curlOptions = array(); |
| 313 | + |
264 | 314 | public function execute() { |
| 315 | + parent::execute(); |
265 | 316 | if ( !$this->status->isOK() ) { |
266 | 317 | return $this->status; |
267 | 318 | } |
268 | 319 | |
269 | | - $this->setCallback( array( $this, 'read' ) ); |
| 320 | + // A lot of the action up front should probably be in |
| 321 | + // set* methods, but we'll leave that for another time. |
270 | 322 | |
271 | | - curl_setopt( $this->curlHandle, CURLOPT_TIMEOUT, $this->timeout ); |
272 | | - curl_setopt( $this->curlHandle, CURLOPT_USERAGENT, Http::userAgent() ); |
273 | | - curl_setopt( $this->curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 ); |
| 323 | + $this->curlOptions[CURLOPT_PROXY] = $this->proxy; |
| 324 | + $this->curlOptions[CURLOPT_TIMEOUT] = $this->timeout; |
| 325 | + $this->curlOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0; |
| 326 | + $this->curlOptions[CURLOPT_WRITEFUNCTION] = $this->callback; |
274 | 327 | |
| 328 | + /* not sure these two are actually necessary */ |
| 329 | + if(isset($this->reqHeaders['Referer'])) { |
| 330 | + $this->curlOptions[CURLOPT_REFERER] = $this->reqHeaders['Referer']; |
| 331 | + } |
| 332 | + $this->curlOptions[CURLOPT_USERAGENT] = $this->reqHeaders['User-Agent']; |
| 333 | + |
275 | 334 | if ( $this->sslVerifyHost ) { |
276 | | - curl_setopt( $this->curlHandle, CURLOPT_SSL_VERIFYHOST, $this->sslVerifyHost ); |
| 335 | + $this->curlOptions[CURLOPT_SSL_VERIFYHOST] = $this->sslVerifyHost; |
277 | 336 | } |
278 | 337 | |
279 | 338 | if ( $this->caInfo ) { |
280 | | - curl_setopt( $this->curlHandle, CURLOPT_CAINFO, $this->caInfo ); |
| 339 | + $this->curlOptions[CURLOPT_CAINFO] = $this->caInfo; |
281 | 340 | } |
282 | 341 | |
283 | 342 | if ( $this->headersOnly ) { |
284 | | - curl_setopt( $this->curlHandle, CURLOPT_NOBODY, true ); |
285 | | - curl_setopt( $this->curlHandle, CURLOPT_HEADER, true ); |
| 343 | + $this->curlOptions[CURLOPT_NOBODY] = true; |
| 344 | + $this->curlOptions[CURLOPT_HEADER] = true; |
286 | 345 | } elseif ( $this->method == 'POST' ) { |
287 | | - curl_setopt( $this->curlHandle, CURLOPT_POST, true ); |
288 | | - curl_setopt( $this->curlHandle, CURLOPT_POSTFIELDS, $this->postdata ); |
| 346 | + $this->curlOptions[CURLOPT_POST] = true; |
| 347 | + $this->curlOptions[CURLOPT_POSTFIELDS] = $this->postData; |
289 | 348 | // Suppress 'Expect: 100-continue' header, as some servers |
290 | 349 | // will reject it with a 417 and Curl won't auto retry |
291 | 350 | // with HTTP 1.0 fallback |
292 | | - curl_setopt( $this->curlHandle, CURLOPT_HTTPHEADER, array( 'Expect:' ) ); |
| 351 | + $this->reqHeaders['Expect'] = ''; |
293 | 352 | } else { |
294 | | - curl_setopt( $this->curlHandle, CURLOPT_CUSTOMREQUEST, $this->method ); |
| 353 | + $this->curlOptions[CURLOPT_CUSTOMREQUEST] = $this->method; |
295 | 354 | } |
296 | 355 | |
297 | | - try { |
298 | | - if ( false === curl_exec( $this->curlHandle ) ) { |
299 | | - $this->status->fatal( 'Error sending request (#$1): $2', |
300 | | - curl_errno( $this->curlHandle ), |
301 | | - curl_error( $this->curlHandle ) ); |
302 | | - } |
303 | | - } catch ( Exception $e ) { |
304 | | - $errno = curl_errno( $this->curlHandle ); |
305 | | - if ( $errno != CURLE_OK ) { |
306 | | - $errstr = curl_error( $this->curlHandle ); |
307 | | - $this->status->fatal( 'CURL error code $1: $2', $errno, $errstr ); |
308 | | - } |
| 356 | + $this->curlOptions[CURLOPT_HTTPHEADER] = $this->getHeaderList(); |
| 357 | + |
| 358 | + $curlHandle = curl_init( $this->url ); |
| 359 | + curl_setopt_array( $curlHandle, $this->curlOptions ); |
| 360 | + |
| 361 | + if ( false === curl_exec( $curlHandle ) ) { |
| 362 | + // re-using already translated error messages |
| 363 | + $this->status->fatal( 'upload-curl-error'.curl_errno( $curlHandle ).'-text' ); |
309 | 364 | } |
310 | 365 | |
311 | | - curl_close( $this->curlHandle ); |
| 366 | + curl_close( $curlHandle ); |
312 | 367 | |
313 | 368 | return $this->status; |
314 | 369 | } |
315 | | - |
316 | | - public function read( $curlH, $content ) { |
317 | | - $this->content .= $content; |
318 | | - return strlen( $content ); |
319 | | - } |
320 | | - |
321 | | - public function getCode() { |
322 | | - # Don't return truncated output |
323 | | - $code = curl_getinfo( $this->curlHandle, CURLINFO_HTTP_CODE ); |
324 | | - if ( $code < 400 ) { |
325 | | - $this->status->setResult( true, $code ); |
326 | | - } else { |
327 | | - $this->status->setResult( false, $code ); |
328 | | - } |
329 | | - } |
330 | 370 | } |
331 | 371 | |
332 | 372 | class PhpHttpRequest extends HttpRequest { |
333 | | - private $reqHeaders; |
334 | | - private $callback; |
335 | 373 | private $fh; |
336 | 374 | |
337 | | - public function initRequest() { |
338 | | - $this->setCallback( array( $this, 'read' ) ); |
339 | | - |
340 | | - $this->reqHeaders[] = "User-Agent: " . Http::userAgent(); |
341 | | - $this->reqHeaders[] = "Accept: */*"; |
342 | | - if ( $this->method == 'POST' ) { |
343 | | - // Required for HTTP 1.0 POSTs |
344 | | - $this->reqHeaders[] = "Content-Length: " . strlen( $this->postdata ); |
345 | | - $this->reqHeaders[] = "Content-type: application/x-www-form-urlencoded"; |
346 | | - } |
347 | | - |
348 | | - if ( $this->parsed_url['scheme'] != 'http' ) { |
349 | | - $this->status->fatal( "Only http:// is supported currently." ); |
350 | | - } |
351 | | - } |
352 | | - |
353 | 375 | protected function urlToTcp( $url ) { |
354 | | - $parsed_url = parse_url( $url ); |
| 376 | + $parsedUrl = parse_url( $url ); |
355 | 377 | |
356 | | - return 'tcp://' . $parsed_url['host'] . ':' . $parsed_url['port']; |
| 378 | + return 'tcp://' . $parsedUrl['host'] . ':' . $parsedUrl['port']; |
357 | 379 | } |
358 | 380 | |
359 | | - public function proxySetup() { |
360 | | - global $wgHTTPProxy; |
| 381 | + public function execute() { |
| 382 | + if ( $this->parsedUrl['scheme'] != 'http' ) { |
| 383 | + $this->status->fatal( 'http-invalid-scheme', $this->parsedURL['scheme'] ); |
| 384 | + } |
361 | 385 | |
362 | | - if ( Http::isLocalURL( $this->url ) ) { |
363 | | - $this->proxy = 'http://localhost:80/'; |
364 | | - } elseif ( $wgHTTPProxy ) { |
365 | | - $this->proxy = $wgHTTPProxy ; |
| 386 | + parent::execute(); |
| 387 | + if ( !$this->status->isOK() ) { |
| 388 | + return $this->status; |
366 | 389 | } |
367 | | - } |
368 | 390 | |
369 | | - public function setReferrer( $url ) { |
370 | | - $this->reqHeaders[] = "Referer: $url"; |
371 | | - } |
| 391 | + // A lot of the action up front should probably be in |
| 392 | + // set* methods, but we'll leave that for another time. |
372 | 393 | |
373 | | - public function setCallback( $cb ) { |
374 | | - $this->callback = $cb; |
375 | | - } |
376 | | - |
377 | | - public function read( $fh, $contents ) { |
378 | | - if ( $this->headersOnly ) { |
379 | | - return false; |
| 394 | + $this->reqHeaders['Accept'] = "*/*"; |
| 395 | + if ( $this->method == 'POST' ) { |
| 396 | + // Required for HTTP 1.0 POSTs |
| 397 | + $this->reqHeaders['Content-Length'] = strlen( $this->postData ); |
| 398 | + $this->reqHeaders['Content-type'] = "application/x-www-form-urlencoded"; |
380 | 399 | } |
381 | | - $this->content .= $contents; |
382 | 400 | |
383 | | - return strlen( $contents ); |
384 | | - } |
385 | | - |
386 | | - public function execute() { |
387 | | - if ( !$this->status->isOK() ) { |
388 | | - return $this->status; |
| 401 | + $options = array(); |
| 402 | + if ( $this->proxy && !$this->noProxy ) { |
| 403 | + $options['proxy'] = $this->urlToTCP( $this->proxy ); |
| 404 | + $options['request_fulluri'] = true; |
389 | 405 | } |
390 | 406 | |
391 | | - $opts = array(); |
392 | | - if ( $this->proxy && !$this->no_proxy ) { |
393 | | - $opts['proxy'] = $this->urlToTCP( $this->proxy ); |
394 | | - $opts['request_fulluri'] = true; |
395 | | - } |
396 | | - |
397 | | - $opts['method'] = $this->method; |
398 | | - $opts['timeout'] = $this->timeout; |
399 | | - $opts['header'] = implode( "\r\n", $this->reqHeaders ); |
| 407 | + $options['method'] = $this->method; |
| 408 | + $options['timeout'] = $this->timeout; |
| 409 | + $options['header'] = implode("\r\n", $this->getHeaderList()); |
400 | 410 | // FOR NOW: Force everyone to HTTP 1.0 |
401 | 411 | /* if ( version_compare( "5.3.0", phpversion(), ">" ) ) { */ |
402 | | - $opts['protocol_version'] = "1.0"; |
| 412 | + $options['protocol_version'] = "1.0"; |
403 | 413 | /* } else { */ |
404 | | - /* $opts['protocol_version'] = "1.1"; */ |
| 414 | + /* $options['protocol_version'] = "1.1"; */ |
405 | 415 | /* } */ |
406 | 416 | |
407 | | - if ( $this->postdata ) { |
408 | | - $opts['content'] = $this->postdata; |
| 417 | + if ( $this->postData ) { |
| 418 | + $options['content'] = $this->postData; |
409 | 419 | } |
410 | 420 | |
411 | | - $context = stream_context_create( array( 'http' => $opts ) ); |
| 421 | + $context = stream_context_create( array( 'http' => $options ) ); |
412 | 422 | try { |
413 | 423 | $this->fh = fopen( $this->url, "r", false, $context ); |
414 | 424 | } catch ( Exception $e ) { |
415 | | - $this->status->fatal( $e->getMessage() ); |
| 425 | + $this->status->fatal( $e->getMessage() ); /* need some l10n help */ |
416 | 426 | return $this->status; |
417 | 427 | } |
418 | 428 | |
419 | 429 | $result = stream_get_meta_data( $this->fh ); |
420 | 430 | if ( $result['timed_out'] ) { |
421 | | - $this->status->error( 'The request timed out' ); |
| 431 | + $this->status->fatal( 'http-timed-out', $this->url ); |
| 432 | + return $this->status; |
422 | 433 | } |
423 | 434 | |
424 | 435 | $this->headers = $result['wrapper_data']; |
— | — | @@ -425,7 +436,10 @@ |
426 | 437 | $end = false; |
427 | 438 | while ( !$end ) { |
428 | 439 | $contents = fread( $this->fh, 8192 ); |
429 | | - $size = call_user_func_array( $this->callback, array( $this->fh, $contents ) ); |
| 440 | + $size = 0; |
| 441 | + if ( $contents ) { |
| 442 | + $size = call_user_func_array( $this->callback, array( $this->fh, $contents ) ); |
| 443 | + } |
430 | 444 | $end = ( $size == 0 ) || feof( $this->fh ); |
431 | 445 | } |
432 | 446 | fclose( $this->fh ); |