/**
  * @param string $requestString
  * @return wfWAFRequest
  */
 public static function parseString($requestString)
 {
     if (!is_string($requestString)) {
         throw new InvalidArgumentException(__METHOD__ . ' expects a string for first parameter, recieved ' . gettype($requestString));
     }
     if (version_compare(phpversion(), '5.3.0') > 0) {
         $class = get_called_class();
         $request = new $class();
     } else {
         $request = new self();
     }
     $request->setAuth(array());
     $request->setBody(array());
     $request->setMd5Body(array());
     $request->setCookies(array());
     $request->setFileNames(array());
     $request->setFiles(array());
     $request->setHeaders(array());
     $request->setHost('');
     $request->setIP('');
     $request->setMethod('');
     $request->setPath('');
     $request->setProtocol('');
     $request->setQueryString(array());
     $request->setMd5QueryString(array());
     $request->setTimestamp('');
     $request->setURI('');
     list($headersString, $bodyString) = explode("\n\n", $requestString, 2);
     $headersString = trim($headersString);
     $bodyString = trim($bodyString);
     $headers = explode("\n", $headersString);
     // Assume first is method
     if (preg_match('/^([a-z]+) (.*?) HTTP\\/1.[0-9]/i', $headers[0], $matches)) {
         $request->setMethod($matches[1]);
         $uri = $matches[2];
         $request->setUri($uri);
         if (($pos = wfWAFUtils::strpos($uri, '?')) !== false) {
             $queryString = wfWAFUtils::substr($uri, $pos + 1);
             parse_str($queryString, $queryStringArray);
             $request->setQueryString($queryStringArray);
             $path = wfWAFUtils::substr($uri, 0, $pos);
             $request->setPath($path);
         } else {
             $request->setPath($uri);
         }
     }
     $kvHeaders = array();
     for ($i = 1; $i < count($headers); $i++) {
         $headerString = $headers[$i];
         list($header, $headerValue) = explode(':', $headerString, 2);
         $header = trim($header);
         $headerValue = trim($headerValue);
         $kvHeaders[$header] = $headerValue;
         switch (wfWAFUtils::strtolower($header)) {
             case 'authorization':
                 if (preg_match('/basic ([A-Za-z0-9\\+\\/=]+)/i', $headerValue, $matches)) {
                     list($authUser, $authPass) = explode(':', base64_decode($matches[1]), 2);
                     $auth['user'] = $authUser;
                     $auth['password'] = $authPass;
                     $request->setAuth($auth);
                 }
                 break;
             case 'host':
                 $request->setHost($headerValue);
                 break;
             case 'cookie':
                 $cookieArray = array();
                 $cookies = str_replace('&', '%26', $headerValue);
                 $cookies = preg_replace('/\\s*;\\s*/', '&', $cookies);
                 parse_str($cookies, $cookieArray);
                 $request->setCookies($cookieArray);
                 break;
         }
     }
     $request->setHeaders($kvHeaders);
     if (wfWAFUtils::strlen($bodyString) > 0) {
         if (preg_match('/^multipart\\/form\\-data; boundary=(.*?)$/i', $request->getHeaders('Content-Type'), $boundaryMatches)) {
             $body = '';
             $files = array();
             $fileNames = array();
             $boundary = $boundaryMatches[1];
             $bodyChunks = explode("--{$boundary}", $bodyString);
             foreach ($bodyChunks as $chunk) {
                 if (!$chunk || $chunk == '--') {
                     continue;
                 }
                 list($chunkHeaders, $chunkData) = explode("\n\n", $chunk, 2);
                 $chunkHeaders = explode("\n", $chunkHeaders);
                 $param = array('value' => wfWAFUtils::substr($chunkData, 0, -1));
                 foreach ($chunkHeaders as $chunkHeader) {
                     if (wfWAFUtils::strpos($chunkHeader, ':') !== false) {
                         list($chunkHeaderKey, $chunkHeaderValue) = explode(':', $chunkHeader, 2);
                         $chunkHeaderKey = trim($chunkHeaderKey);
                         $chunkHeaderValue = trim($chunkHeaderValue);
                         switch ($chunkHeaderKey) {
                             case 'Content-Disposition':
                                 $dataAttributes = explode(';', $chunkHeaderValue);
                                 foreach ($dataAttributes as $attr) {
                                     $attr = trim($attr);
                                     if (preg_match('/^name="(.*?)"$/i', $attr, $attrMatch)) {
                                         $param['name'] = $attrMatch[1];
                                         continue;
                                     }
                                     if (preg_match('/^filename="(.*?)"$/i', $attr, $attrMatch)) {
                                         $param['filename'] = $attrMatch[1];
                                         continue;
                                     }
                                 }
                                 break;
                             case 'Content-Type':
                                 $param['type'] = $chunkHeaderValue;
                                 break;
                         }
                     }
                 }
                 if (array_key_exists('name', $param)) {
                     if (array_key_exists('filename', $param)) {
                         $files[$param['name']] = array('name' => $param['filename'], 'type' => $param['type'], 'size' => wfWAFUtils::strlen($param['value']), 'content' => $param['value']);
                         $fileNames[$param['name']] = $param['filename'];
                     } else {
                         $body .= urlencode($param['name']) . '=' . urlencode($param['value']) . '&';
                     }
                 }
             }
             if ($body) {
                 parse_str($body, $postBody);
                 if (is_array($postBody)) {
                     $request->setBody($postBody);
                 } else {
                     $request->setBody($body);
                 }
             }
             if ($files) {
                 $request->setFiles($files);
             }
             if ($fileNames) {
                 $request->setFileNames($fileNames);
             }
         } else {
             parse_str($bodyString, $postBody);
             if (is_array($postBody)) {
                 $request->setBody($postBody);
             } else {
                 $request->setBody($bodyString);
             }
         }
     }
     return $request;
 }