From: Paul J R Date: Thu, 25 Oct 2012 06:14:31 +0000 (+1100) Subject: handling data from the client properly for gzdecoding and X-Git-Url: http://git.pjr.cc/?a=commitdiff_plain;h=7c855df8f42cc8508f556068a707c9258cd40e43;p=gwvp-mini.git handling data from the client properly for gzdecoding and receiving/sending properly.... painful experience --- diff --git a/gwvpmini/gwvpmini_gitbackend.php b/gwvpmini/gwvpmini_gitbackend.php index 27ccee7..424c108 100644 --- a/gwvpmini/gwvpmini_gitbackend.php +++ b/gwvpmini/gwvpmini_gitbackend.php @@ -289,14 +289,6 @@ function gwvpmini_callGitBackend($username, $repo) error_log("path trans'd is /$repo_base/$repo.git/$euri from $ruri with ".$_REQUEST["q"]." $strrem pre is ".print_r($_REQUEST,true)." and foff ".print_r($headers, true)); - if(isset($headers["Content-Encoding"])) { - if($headers["Content-Encoding"] == "gzip") { - error_log("DAM YOU GIT CLIENT"); - } - } - - - $pwd = "/$repo_base/"; $proc = proc_open("/usr/lib/git-core/git-http-backend", array(array("pipe","rb"),array("pipe","wb"),array("file","/tmp/err", "a")), $pipes, $pwd, $procenv); @@ -332,19 +324,29 @@ function gwvpmini_callGitBackend($username, $repo) $stlimit = 0; $fp = fopen("/tmp/gitup.".rand(0,4000000), "w"); + $from_client_data = ""; // i was going to use stream_select, but i feel this works better like this while($continue) { // do client + + // lets start again.... + if(!feof($fh)) { - $from_client_data = fread($fh,8192); + if(isset($headers["Content-Length"])) { + $cl = $headers["Content-Length"]; + while(strlen($from_client_data) < $cl) { + error_log("re-read ".strlen($from_client_data)); + $from_client_data .= fread($fh, $cl); + } + } else $from_client_data = fread($fh,8192); - // TODO: BIG TODO: must rewrite this bit. I need to read the entire client bit if its posting in one piece so i can then decode. - // if the client sends more then 8192, i could be very well screwed. must handle content-length on read... + // TODO: BIG TODO: must rewrite this bit. its ugly as sin, it works, but it probably shouldnt. if(isset($headers["Content-Encoding"])) { if($headers["Content-Encoding"] == "gzip") { //error_log("DAM YOU GIT CLIENT and your retarded gzip encoding"); $from_client_data = gzinflate(substr($from_client_data, 10)); + //$from_client_data = gzdecode($from_client_data); } } if($from_client_data !== false) { @@ -389,6 +391,7 @@ function gwvpmini_callGitBackend($username, $repo) } if($from_cgi_data !== false) { + error_log("send to client"); echo $from_cgi_data; flush(); } @@ -398,18 +401,20 @@ function gwvpmini_callGitBackend($username, $repo) $cgi_len = 0; } + flush(); + if(feof($pipes[1])) $continue = false; else { if($client_len == 0 && $cgi_len == 0) { usleep(200000); error_log("sleep tick"); $stlimit++; - if($stlimit > 50) $continue = false; + if($stlimit > 5000) $continue = false; } else { $stlimit = 0; error_log("sizes: $client_len, $cgi_len"); if($cgi_len > 0) { - error_log("from cgi: \"$from_cgi_data\""); + //error_log("from cgi: \"$from_cgi_data\""); } } } @@ -480,4 +485,115 @@ function gwvpmini_createGitRepo($name, $ownerid, $desc, $defperms, $clonefrom, $ return true; } +function gzdecode($data,&$filename='',&$error='',$maxlength=null) +{ + $len = strlen($data); + if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) { + $error = "Not in GZIP format."; + return null; // Not GZIP format (See RFC 1952) + } + $method = ord(substr($data,2,1)); // Compression method + $flags = ord(substr($data,3,1)); // Flags + if ($flags & 31 != $flags) { + $error = "Reserved bits not allowed."; + return null; + } + // NOTE: $mtime may be negative (PHP integer limitations) + $mtime = unpack("V", substr($data,4,4)); + $mtime = $mtime[1]; + $xfl = substr($data,8,1); + $os = substr($data,8,1); + $headerlen = 10; + $extralen = 0; + $extra = ""; + if ($flags & 4) { + // 2-byte length prefixed EXTRA data in header + if ($len - $headerlen - 2 < 8) { + return false; // invalid + } + $extralen = unpack("v",substr($data,8,2)); + $extralen = $extralen[1]; + if ($len - $headerlen - 2 - $extralen < 8) { + return false; // invalid + } + $extra = substr($data,10,$extralen); + $headerlen += 2 + $extralen; + } + $filenamelen = 0; + $filename = ""; + if ($flags & 8) { + // C-style string + if ($len - $headerlen - 1 < 8) { + return false; // invalid + } + $filenamelen = strpos(substr($data,$headerlen),chr(0)); + if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) { + return false; // invalid + } + $filename = substr($data,$headerlen,$filenamelen); + $headerlen += $filenamelen + 1; + } + $commentlen = 0; + $comment = ""; + if ($flags & 16) { + // C-style string COMMENT data in header + if ($len - $headerlen - 1 < 8) { + return false; // invalid + } + $commentlen = strpos(substr($data,$headerlen),chr(0)); + if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) { + return false; // Invalid header format + } + $comment = substr($data,$headerlen,$commentlen); + $headerlen += $commentlen + 1; + } + $headercrc = ""; + if ($flags & 2) { + // 2-bytes (lowest order) of CRC32 on header present + if ($len - $headerlen - 2 < 8) { + return false; // invalid + } + $calccrc = crc32(substr($data,0,$headerlen)) & 0xffff; + $headercrc = unpack("v", substr($data,$headerlen,2)); + $headercrc = $headercrc[1]; + if ($headercrc != $calccrc) { + $error = "Header checksum failed."; + return false; // Bad header CRC + } + $headerlen += 2; + } + // GZIP FOOTER + $datacrc = unpack("V",substr($data,-8,4)); + $datacrc = sprintf('%u',$datacrc[1] & 0xFFFFFFFF); + $isize = unpack("V",substr($data,-4)); + $isize = $isize[1]; + // decompression: + $bodylen = $len-$headerlen-8; + if ($bodylen < 1) { + // IMPLEMENTATION BUG! + return null; + } + $body = substr($data,$headerlen,$bodylen); + $data = ""; + if ($bodylen > 0) { + switch ($method) { + case 8: + // Currently the only supported compression method: + $data = gzinflate($body,$maxlength); + break; + default: + $error = "Unknown compression method."; + return false; + } + } // zero-byte body content is allowed + // Verifiy CRC32 + $crc = sprintf("%u",crc32($data)); + $crcOK = $crc == $datacrc; + $lenOK = $isize == strlen($data); + if (!$lenOK || !$crcOK) { + $error = ( $lenOK ? '' : 'Length check FAILED. ') . ( $crcOK ? '' : 'Checksum FAILED.'); + return false; + } + return $data; +} ?> \ No newline at end of file