/**
  *	This is our implementation of the query function from the IXR_Client class so that we can use the
  *	YDHttpClient class to do the HTTP stuff.
  */
 function query()
 {
     // Get the function arguments
     $args = func_get_args();
     $method = array_shift($args);
     // Create a new request
     $request = new IXR_Request($method, $args);
     // Create a new HTTP client
     $client = new YDHttpClient($this->server, $this->port);
     if (isset($this->timeout)) {
         $client->setTimeout($this->timeout);
     }
     $client->useGzip(true);
     $client->setDebug(YDConfig::get('YD_DEBUG'));
     $client->path = $this->path;
     $client->method = 'POST';
     $client->contenttype = 'text/xml';
     $client->postdata = str_replace("\n", '', $request->getXml());
     $client->handle_redirects = false;
     // Show in debugging mode
     if ($this->debug) {
         $tmp = htmlspecialchars($client->postdata);
         echo '<pre>' . $tmp . YD_CRLF . '</pre>' . YD_CRLF . YD_CRLF;
     }
     // Now send the request
     $result = $client->doRequest();
     // Die with an error if any
     if (!$result) {
         $this->error = new IXR_Error(-32300, $client->getError());
         return false;
     }
     // Get the contents
     $contents = $client->getContent();
     // Show in debugging mode
     if ($this->debug) {
         $tmp = htmlspecialchars($contents);
         echo '<pre>' . $tmp . YD_CRLF . '</pre>' . YD_CRLF . YD_CRLF;
     }
     // Now parse what we've got back
     $this->message = new IXR_Message($contents);
     if (!$this->message->parse()) {
         $this->error = new IXR_Error(-32700, 'parse error. not well formed');
         return false;
     }
     // Is the message a fault?
     if ($this->message->messageType == 'fault') {
         $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
         return false;
     }
     // Message must be OK
     return true;
 }
 function doRequest()
 {
     // Performs the actual HTTP request, returning true or false depending on outcome
     if (!($fp = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout))) {
         // Set error message
         switch ($errno) {
             case -3:
                 $this->errormsg = 'Socket creation failed (-3)';
             case -4:
                 $this->errormsg = 'DNS lookup failure (-4)';
             case -5:
                 $this->errormsg = 'Connection refused or timed out (-5)';
             default:
                 $this->errormsg = 'Connection failed (' . $errno . ')';
                 $this->errormsg .= ' ' . $errstr;
                 $this->debug($this->errormsg);
         }
         return false;
     }
     socket_set_timeout($fp, $this->timeout);
     $request = $this->buildRequest();
     $this->debug('Request', $request);
     fwrite($fp, $request);
     // Reset all the variables that should not persist between requests
     $this->headers = array();
     $this->content = '';
     $this->errormsg = '';
     // Set a couple of flags
     $inHeaders = true;
     $atStart = true;
     // Now start reading back the response
     while (!feof($fp)) {
         $line = fgets($fp, 4096);
         if ($atStart) {
             // Deal with first line of returned data
             $atStart = false;
             if (!preg_match('/HTTP\\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $line, $m)) {
                 $this->errormsg = "Status code line invalid: " . htmlentities($line);
                 $this->debug($this->errormsg);
                 return false;
             }
             $http_version = $m[1];
             // not used
             $this->status = $m[2];
             $status_string = $m[3];
             // not used
             $this->debug(trim($line));
             continue;
         }
         if ($inHeaders) {
             if (trim($line) == '') {
                 $inHeaders = false;
                 $this->debug('Received Headers', $this->headers);
                 if ($this->headers_only) {
                     break;
                     // Skip the rest of the input
                 }
                 continue;
             }
             if (!preg_match('/([^:]+):\\s*(.*)/', $line, $m)) {
                 // Skip to the next header
                 continue;
             }
             $key = strtolower(trim($m[1]));
             $val = trim($m[2]);
             // Deal with the possibility of multiple headers of same name
             if (isset($this->headers[$key])) {
                 if (is_array($this->headers[$key])) {
                     $this->headers[$key][] = $val;
                 } else {
                     $this->headers[$key] = array($this->headers[$key], $val);
                 }
             } else {
                 $this->headers[$key] = $val;
             }
             continue;
         }
         // We're not in the headers, so append the line to the contents
         $this->content .= $line;
     }
     fclose($fp);
     // If data is compressed, uncompress it
     if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] == 'gzip') {
         $this->debug('Content is gzip encoded, unzipping it');
         $this->content = substr($this->content, 10);
         // See http://www.php.net/manual/en/function.gzencode.php
         $this->content = gzinflate($this->content);
     }
     // If $persist_cookies, deal with any cookies
     if ($this->persist_cookies && isset($this->headers['set-cookie']) && $this->host == $this->cookie_host) {
         $cookies = $this->headers['set-cookie'];
         if (!is_array($cookies)) {
             $cookies = array($cookies);
         }
         foreach ($cookies as $cookie) {
             if (preg_match('/([^=]+)=([^;]+);/', $cookie, $m)) {
                 $this->cookies[$m[1]] = $m[2];
             }
         }
         // Record domain of cookies for security reasons
         $this->cookie_host = $this->host;
     }
     // If $persist_referers, set the referer ready for the next request
     if ($this->persist_referers) {
         $this->debug('Persisting referer: ' . $this->getRequestURL());
         $this->referer = $this->getRequestURL();
     }
     // Finally, if handle_redirects and a redirect is sent, do that
     if ($this->handle_redirects) {
         if (++$this->redirect_count >= $this->max_redirects) {
             $this->errormsg = 'Number of redirects exceeded maximum (' . $this->max_redirects . ')';
             $this->debug($this->errormsg);
             $this->redirect_count = 0;
             return false;
         }
         $location = isset($this->headers['location']) ? $this->headers['location'] : '';
         $uri = isset($this->headers['uri']) ? $this->headers['uri'] : '';
         if ($location || $uri) {
             $url = parse_url($location . $uri);
             // This will FAIL if redirect is to a different site
             if (!empty($url['path'])) {
                 return $this->get($url['path']);
             } else {
                 // Note from Rene (rene@fsfe.org): Now it won't fail anymore.
                 // Quick&Dirty hack... don't blame me... :)
                 $u = new YDUrl($this->headers['location']);
                 $c = new YDHttpClient($u->getHost());
                 $c->setUserAgent($this->user_agent);
                 $c->setAuthorization($this->username, $this->password);
                 $c->setCookies($this->cookies);
                 $c->useGzip($this->use_gzip);
                 $c->setPersistCookies($this->persist_cookies);
                 $c->setPersistReferers($this->persist_referers);
                 $c->setHandleRedirects($this->handle_redirects);
                 $c->setMaxRedirects($this->max_redirects);
                 $c->setHeadersOnly($this->headers_only);
                 $c->setDebug($this->debug);
                 $r = $c->get('/' . $u->getPath());
                 $this->status = $c->getStatus();
                 $this->content = $c->getContent();
                 $this->headers = $c->getHeaders();
                 $this->errormsg = $c->getError();
                 $this->cookies = $c->getCookies();
                 return $r;
             }
         }
     }
     return true;
 }