import http from 'http' ; import { spawn } from 'child_process' ; import { Git } from './git' ; import { HttpDuplex } from './http-duplex' ; import { Service , ServiceOptions } from './service' ; import { ServiceString } from './types' ; export function packSideband ( s ) { const n = ( 4 + s . length ) . toString ( 16 ) ; return Array ( 4 - n . length + 1 ) . join ( '0' ) + n + s ; } param res export function noCache ( res ) { res . setHeader ( 'expires' , 'Fri, 01 Jan 1980 00:00:00 GMT' ) ; res . setHeader ( 'pragma' , 'no-cache' ) ; res . setHeader ( 'cache-control' , 'no-cache, max-age=0, must-revalidate' ) ; } param req param res param callback export function basicAuth ( req , res , callback ) { if ( ! req . headers [ 'authorization' ] ) { res . setHeader ( 'Content-Type' , 'text/plain' ) ; res . setHeader ( 'WWW-Authenticate' , 'Basic realm="authorization needed"' ) ; res . writeHead ( 401 ) ; res . end ( '401 Unauthorized' ) ; } else { const tokens = req . headers [ 'authorization' ] . split ( ' ' ) ; if ( tokens [ 0 ] === 'Basic' ) { const splitHash = Buffer . from ( tokens [ 1 ] , 'base64' ) . toString ( 'utf8' ) . split ( ':' ) ; const username = splitHash . shift ( ) ; const password = splitHash . join ( ':' ) ; callback ( username , password ) ; } } } param dup param service param repoLocation param res export function serviceRespond ( dup , service , repoLocation , res ) { res . write ( packSideband ( '# service=git-' + service + '\n' ) ) ; res . write ( '0000' ) ; const isWin = /^win/ . test ( process . platform ) ; const cmd = isWin ? [ 'git' , service , '--stateless-rpc' , '--advertise-refs' , repoLocation ] : [ 'git-' + service , '--stateless-rpc' , '--advertise-refs' , repoLocation ] ; const ps = spawn ( cmd [ 0 ] , cmd . slice ( 1 ) ) ; ps . on ( 'error' , ( err ) => { dup . emit ( 'error' , new Error ( `${ err . message } running command ${ cmd . join ( ' ' ) }` ) ) ; } ) ; ps . stdout . pipe ( res ) ; } param git param repo param service param req param res export function infoResponse ( git , repo , service , req , res ) { function next ( ) { res . setHeader ( 'content-type' , 'application/x-git-' + service + '-advertisement' ) ; noCache ( res ) ; serviceRespond ( git , service , git . dirMap ( repo ) , res ) ; } const dup = new HttpDuplex ( req , res ) ; dup . cwd = git . dirMap ( repo ) ; dup . repo = repo ; dup . accept = dup . emit . bind ( dup , 'accept' ) ; dup . reject = dup . emit . bind ( dup , 'reject' ) ; dup . once ( 'reject' , ( code ) => { res . statusCode = code || 500 ; res . end ( ) ; } ) ; const anyListeners = git . listeners ( 'info' ) . length > 0 ; const exists = git . exists ( repo ) ; dup . exists = exists ; if ( ! exists && git . autoCreate ) { dup . once ( 'accept' , ( ) => { git . create ( repo , next ) ; } ) ; git . emit ( 'info' , dup ) ; if ( ! anyListeners ) dup . accept ( ) ; } else if ( ! exists ) { res . statusCode = 404 ; res . setHeader ( 'content-type' , 'text/plain' ) ; res . end ( 'repository not found' ) ; } else { dup . once ( 'accept' , next ) ; git . emit ( 'info' , dup ) ; if ( ! anyListeners ) dup . accept ( ) ; } } param repo export function parseGitName ( repo ) { const locationOfGit = repo . lastIndexOf ( '.git' ) ; return repo . slice ( 0 , locationOfGit > 0 ? locationOfGit : repo . length ) ; } param opts param req param res export function createAction ( opts , req , res ) { const service = new Service ( opts , req , res ) ; return service ; }