446 $buffer = $this->_read_until_newlines($this->socket); |
446 $buffer = $this->_read_until_newlines($this->socket); |
447 $this->state = 3; |
447 $this->state = 3; |
448 $this->_parse_response_code($buffer); |
448 $this->_parse_response_code($buffer); |
449 $this->response = $buffer; |
449 $this->response = $buffer; |
450 } |
450 } |
|
451 // obey redirects |
|
452 $i = 0; |
|
453 while ( $i < 20 ) |
|
454 { |
|
455 $incoming_headers = $this->get_response_headers_array(); |
|
456 if ( !$incoming_headers ) |
|
457 break; |
|
458 if ( isset($incoming_headers['Location']) ) |
|
459 { |
|
460 // we've been redirected... |
|
461 $new_uri = $this->_resolve_uri($incoming_headers['Location']); |
|
462 if ( !$new_uri ) |
|
463 { |
|
464 // ... bad URI, ignore Location header. |
|
465 break; |
|
466 } |
|
467 // change location |
|
468 $this->host = $new_uri['host']; |
|
469 $this->port = $new_uri['port']; |
|
470 $this->uri = $new_uri['uri']; |
|
471 $get = ''; |
|
472 |
|
473 // reset |
|
474 $this->sock_close($this->socket); |
|
475 $this->_sock_open($this->socket); |
|
476 $this->_write_request($this->socket, $headers, $cookies, $get, $post); |
|
477 $buffer = $this->_read_until_newlines($this->socket); |
|
478 $this->state = 3; |
|
479 $this->_parse_response_code($buffer); |
|
480 $this->response = $buffer; |
|
481 $i++; |
|
482 } |
|
483 else |
|
484 { |
|
485 break; |
|
486 } |
|
487 } |
|
488 if ( $i == 20 ) |
|
489 { |
|
490 throw new Exception(__METHOD__ . ": Redirect trap. Request_HTTP doesn't do cookies, btw."); |
|
491 } |
|
492 |
451 if ( $this->state == 3 ) |
493 if ( $this->state == 3 ) |
452 { |
494 { |
453 // Determine transfer encoding |
495 // Determine transfer encoding |
454 $is_chunked = preg_match("/Transfer-Encoding: (chunked)\r?\n/", $this->response); |
496 $is_chunked = preg_match("/Transfer-Encoding: (chunked)\r?\n/", $this->response); |
455 |
497 if ( preg_match("/^Content-Length: ([0-9]+)[\s]*$/mi", $this->response, $match) && !$is_chunked ) |
456 $buffer = ''; |
498 { |
457 while ( !feof($this->socket) ) |
499 $size = intval($match[1]); |
458 { |
500 if ( $this->debug ) |
459 $part = fgets($this->socket, 1024); |
|
460 if ( $is_chunked && preg_match("/^([a-f0-9]+)\x0D\x0A$/", $part, $match) ) |
|
461 { |
501 { |
462 $chunklen = hexdec($match[1]); |
502 echo "Pulling response using fread(), size $size\n"; |
463 $part = ( $chunklen > 0 ) ? fread($this->socket, $chunklen) : ''; |
|
464 // remove the last newline from $part |
|
465 $part = preg_replace("/\r?\n\$/m", "", $part); |
|
466 } |
503 } |
467 $buffer .= $part; |
504 $this->response .= fread($this->socket, $size); |
468 } |
505 } |
469 $this->response .= $buffer; |
506 else |
|
507 { |
|
508 if ( $this->debug ) |
|
509 echo "Pulling response using chunked handler\n"; |
|
510 |
|
511 $buffer = ''; |
|
512 while ( !feof($this->socket) ) |
|
513 { |
|
514 $part = fgets($this->socket, 1024); |
|
515 if ( $is_chunked && preg_match("/^([a-f0-9]+)\x0D\x0A$/", $part, $match) ) |
|
516 { |
|
517 $chunklen = hexdec($match[1]); |
|
518 $part = ( $chunklen > 0 ) ? fread($this->socket, $chunklen) : ''; |
|
519 // remove the last newline from $part |
|
520 $part = preg_replace("/\r?\n\$/", "", $part); |
|
521 } |
|
522 $buffer .= $part; |
|
523 } |
|
524 $this->response .= $buffer; |
|
525 } |
470 } |
526 } |
471 $this->state = 4; |
527 $this->state = 4; |
472 |
528 |
473 $this->sock_close($this->socket); |
529 $this->sock_close($this->socket); |
474 $this->socket = false; |
530 $this->socket = false; |
637 $this->state = 0; |
693 $this->state = 0; |
638 return ($bandwidth_exceeded) ? false : true; |
694 return ($bandwidth_exceeded) ? false : true; |
639 } |
695 } |
640 |
696 |
641 /** |
697 /** |
|
698 * Resolves, based on current settings and URI, a URI string to an array consisting of a host, port, and new URI. Returns false on error. |
|
699 * @param string |
|
700 * @return array |
|
701 */ |
|
702 |
|
703 function _resolve_uri($uri) |
|
704 { |
|
705 // long ass regexp w00t |
|
706 if ( !preg_match('#^(?:https?://((?:(?:[a-z0-9-]+\.)*)(?:[a-z0-9-]+)|\[[a-f0-9:]+\])(?::([0-9]+))?)?(/)(.*)$#i', $uri, $match) ) |
|
707 { |
|
708 // bad target URI |
|
709 return false; |
|
710 } |
|
711 $hostpart = $match[1]; |
|
712 if ( empty($hostpart) ) |
|
713 { |
|
714 // use existing host |
|
715 $host = $this->host; |
|
716 $port = $this->port; |
|
717 } |
|
718 else |
|
719 { |
|
720 $host = $match[1]; |
|
721 $port = empty($match[2]) ? 80 : intval($match[2]); |
|
722 } |
|
723 // is this an absolute URI, or relative? |
|
724 if ( empty($match[3]) ) |
|
725 { |
|
726 // relative |
|
727 $uri = dirname($this->uri) . $match[4]; |
|
728 } |
|
729 else |
|
730 { |
|
731 // absolute |
|
732 $uri = '/' . $match[4]; |
|
733 } |
|
734 return array( |
|
735 'host' => $host, |
|
736 'port' => $port, |
|
737 'uri' => $uri |
|
738 ); |
|
739 } |
|
740 |
|
741 /** |
642 * Returns only the response headers. |
742 * Returns only the response headers. |
643 * @return string |
743 * @return string |
644 */ |
744 */ |
645 |
745 |
646 function get_response_headers() |
746 function get_response_headers() |
650 return $this->response; |
750 return $this->response; |
651 } |
751 } |
652 else if ( $this->state == 4 ) |
752 else if ( $this->state == 4 ) |
653 { |
753 { |
654 $pos_end = strpos($this->response, "\r\n\r\n"); |
754 $pos_end = strpos($this->response, "\r\n\r\n"); |
655 $data = substr($this->response, 0, $pos_start); |
755 if ( empty($pos_end) ) |
|
756 { |
|
757 $pos_end = strpos($this->response, "\n\n"); |
|
758 } |
|
759 $data = substr($this->response, 0, $pos_end); |
656 return $data; |
760 return $data; |
657 } |
761 } |
658 else |
762 else |
659 { |
763 { |
660 $this->_send_request_headers_only(); |
764 $this->_send_request_headers_only(); |