@@ -331,9 +331,63 @@ static int get_protocol_http_header(enum protocol_version version,
331331 return 0 ;
332332}
333333
334+ static void check_smart_http (struct discovery * d , const char * service ,
335+ struct strbuf * type )
336+ {
337+ const char * p ;
338+ struct packet_reader reader ;
339+
340+ /*
341+ * If we don't see x-$service-advertisement, then it's not smart-http.
342+ * But once we do, we commit to it and assume any other protocol
343+ * violations are hard errors.
344+ */
345+ if (!skip_prefix (type -> buf , "application/x-" , & p ) ||
346+ !skip_prefix (p , service , & p ) ||
347+ strcmp (p , "-advertisement" ))
348+ return ;
349+
350+ packet_reader_init (& reader , -1 , d -> buf , d -> len ,
351+ PACKET_READ_CHOMP_NEWLINE |
352+ PACKET_READ_DIE_ON_ERR_PACKET );
353+ if (packet_reader_read (& reader ) != PACKET_READ_NORMAL )
354+ die ("invalid server response; expected service, got flush packet" );
355+
356+ if (skip_prefix (reader .line , "# service=" , & p ) && !strcmp (p , service )) {
357+ /*
358+ * The header can include additional metadata lines, up
359+ * until a packet flush marker. Ignore these now, but
360+ * in the future we might start to scan them.
361+ */
362+ for (;;) {
363+ packet_reader_read (& reader );
364+ if (reader .pktlen <= 0 ) {
365+ break ;
366+ }
367+ }
368+
369+ /*
370+ * v0 smart http; callers expect us to soak up the
371+ * service and header packets
372+ */
373+ d -> buf = reader .src_buffer ;
374+ d -> len = reader .src_len ;
375+ d -> proto_git = 1 ;
376+
377+ } else if (!strcmp (reader .line , "version 2" )) {
378+ /*
379+ * v2 smart http; do not consume version packet, which will
380+ * be handled elsewhere.
381+ */
382+ d -> proto_git = 1 ;
383+
384+ } else {
385+ die ("invalid server response; got '%s'" , reader .line );
386+ }
387+ }
388+
334389static struct discovery * discover_refs (const char * service , int for_push )
335390{
336- struct strbuf exp = STRBUF_INIT ;
337391 struct strbuf type = STRBUF_INIT ;
338392 struct strbuf charset = STRBUF_INIT ;
339393 struct strbuf buffer = STRBUF_INIT ;
@@ -405,55 +459,15 @@ static struct discovery *discover_refs(const char *service, int for_push)
405459 last -> buf_alloc = strbuf_detach (& buffer , & last -> len );
406460 last -> buf = last -> buf_alloc ;
407461
408- strbuf_addf (& exp , "application/x-%s-advertisement" , service );
409- if (maybe_smart &&
410- (5 <= last -> len && last -> buf [4 ] == '#' ) &&
411- !strbuf_cmp (& exp , & type )) {
412- struct packet_reader reader ;
413- packet_reader_init (& reader , -1 , last -> buf , last -> len ,
414- PACKET_READ_CHOMP_NEWLINE |
415- PACKET_READ_DIE_ON_ERR_PACKET );
416-
417- /*
418- * smart HTTP response; validate that the service
419- * pkt-line matches our request.
420- */
421- if (packet_reader_read (& reader ) != PACKET_READ_NORMAL )
422- die ("invalid server response; expected service, got flush packet" );
423-
424- strbuf_reset (& exp );
425- strbuf_addf (& exp , "# service=%s" , service );
426- if (strcmp (reader .line , exp .buf ))
427- die ("invalid server response; got '%s'" , reader .line );
428- strbuf_release (& exp );
429-
430- /* The header can include additional metadata lines, up
431- * until a packet flush marker. Ignore these now, but
432- * in the future we might start to scan them.
433- */
434- for (;;) {
435- packet_reader_read (& reader );
436- if (reader .pktlen <= 0 ) {
437- break ;
438- }
439- }
440-
441- last -> buf = reader .src_buffer ;
442- last -> len = reader .src_len ;
443-
444- last -> proto_git = 1 ;
445- } else if (maybe_smart &&
446- last -> len > 5 && starts_with (last -> buf + 4 , "version 2" )) {
447- last -> proto_git = 1 ;
448- }
462+ if (maybe_smart )
463+ check_smart_http (last , service , & type );
449464
450465 if (last -> proto_git )
451466 last -> refs = parse_git_refs (last , for_push );
452467 else
453468 last -> refs = parse_info_refs (last );
454469
455470 strbuf_release (& refs_url );
456- strbuf_release (& exp );
457471 strbuf_release (& type );
458472 strbuf_release (& charset );
459473 strbuf_release (& effective_url );
0 commit comments