| | public function render() { |
| | if( $this->subPath === '' ) { |
| | - $this->redirectBrowser(); |
| | - return; |
| | + $uiUrl = str_replace( '.git', '', $_SERVER['REQUEST_URI'] ); |
| | + header( "Location: $uiUrl" ); |
| | + exit; |
| | } |
| | |
 |
| | echo "Read-only repository."; |
| | exit; |
| | - } |
| | - |
| | - if( $this->subPath === 'HEAD' ) { |
| | - $this->serve( 'HEAD', 'text/plain' ); |
| | - return; |
| | } |
| | |
| | + $contentType = 'text/plain'; |
| | if( strpos( $this->subPath, 'objects/' ) === 0 ) { |
| | - $this->serve( $this->subPath, 'application/x-git-object' ); |
| | - return; |
| | + $contentType = 'application/x-git-object'; |
| | } |
| | - |
| | - http_response_code( 404 ); |
| | - echo "Not Found"; |
| | - exit; |
| | - } |
| | |
| | - private function redirectBrowser(): void { |
| | - $uiUrl = str_replace( '.git', '', $_SERVER['REQUEST_URI'] ); |
| | - header( "Location: $uiUrl" ); |
| | - exit; |
| | + $this->serve( $this->subPath, $contentType ); |
| | } |
| | |
| | private function renderInfoRefs(): void { |
| | $service = $_GET['service'] ?? ''; |
| | |
| | - if( empty( $service ) && isset( $_SERVER['QUERY_STRING'] ) ) { |
| | - parse_str( $_SERVER['QUERY_STRING'], $query ); |
| | - $service = $query['service'] ?? ''; |
| | + if( empty( $service ) ) { |
| | + $queryStr = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY ); |
| | + if( $queryStr ) { |
| | + parse_str( $queryStr, $query ); |
| | + $service = $query['service'] ?? ''; |
| | + } |
| | } |
| | |
 |
| | header( 'Cache-Control: no-cache' ); |
| | |
| | - $input = file_get_contents( 'php://input' ); |
| | + $inputHandle = fopen( 'php://input', 'rb' ); |
| | $wants = []; |
| | $haves = []; |
| | - $offset = 0; |
| | |
| | - while( $offset < strlen( $input ) ) { |
| | - $line = $this->readPacketLine( $input, $offset ); |
| | + while( true ) { |
| | + $line = $this->readPacketLine( $inputHandle ); |
| | if( $line === null ) break; |
| | if( $line === '' ) continue; |
| | |
| | $line = trim( $line ); |
| | |
| | if( strpos( $line, 'want ' ) === 0 ) { |
| | - $parts = explode( ' ', $line ); |
| | - $wants[] = $parts[1]; |
| | + $wants[] = substr( $line, 5, 40 ); |
| | } elseif( strpos( $line, 'have ' ) === 0 ) { |
| | - $parts = explode( ' ', $line ); |
| | - $haves[] = $parts[1]; |
| | + $haves[] = substr( $line, 5, 40 ); |
| | } elseif( $line === 'done' ) { |
| | break; |
 |
| | $this->sendSidebandData( 1, $packData ); |
| | $this->packetFlush(); |
| | - |
| | exit; |
| | } |
| | |
| | private function sendSidebandData( int $band, string $data ): void { |
| | - $chunkSize = 65000; |
| | + $chunkSize = 65520; |
| | $offset = 0; |
| | $len = strlen( $data ); |
 |
| | } |
| | |
| | - private function readPacketLine( string $input, int &$offset ): ?string { |
| | - if( $offset + 4 > strlen( $input ) ) { |
| | + private function readPacketLine( $handle ): ?string { |
| | + $lenHex = fread( $handle, 4 ); |
| | + |
| | + if( strlen( $lenHex ) < 4 || !ctype_xdigit( $lenHex ) ) { |
| | return null; |
| | } |
| | - |
| | - $lenHex = substr( $input, $offset, 4 ); |
| | - |
| | - if( !ctype_xdigit( $lenHex ) ) return null; |
| | |
| | $len = hexdec( $lenHex ); |
| | |
| | if( $len === 0 ) { |
| | - $offset += 4; |
| | return ''; |
| | } |
| | |
| | if( $len < 4 ) { |
| | return null; |
| | - } |
| | - |
| | - $offset += 4; |
| | - $dataLen = $len - 4; |
| | - |
| | - if( $offset + $dataLen > strlen( $input ) ) { |
| | - return null; |
| | } |
| | - |
| | - $data = substr( $input, $offset, $dataLen ); |
| | - $offset += $dataLen; |
| | |
| | - return $data; |
| | + $data = fread( $handle, $len - 4 ); |
| | + return $data !== false ? $data : null; |
| | } |
| | |
| | private function serve( string $path, string $contentType ): void { |
| | header( 'Content-Type: ' . $contentType ); |
| | - |
| | - $success = $this->git->streamRaw( $path ); |
| | |
| | - if( !$success ) { |
| | + if( !$this->git->streamRaw( $path ) ) { |
| | http_response_code( 404 ); |
| | - echo "Missing: $path"; |
| | + echo "Not Found"; |
| | } |
| | - |
| | exit; |
| | } |
 |
| | } |
| | } |
| | - |
| | |