@@ -499,8 +499,7 @@ static enum worker_result do__gvfs_config__get(struct req *req)
499
499
* write_object_file_prepare()
500
500
* write_loose_object()
501
501
*/
502
- static enum worker_result send_loose_object (const struct object_info * oi ,
503
- const struct object_id * oid ,
502
+ static enum worker_result send_loose_object (const struct object_id * oid ,
504
503
int fd )
505
504
{
506
505
#define MAX_HEADER_LEN 32
@@ -513,6 +512,42 @@ static enum worker_result send_loose_object(const struct object_info *oi,
513
512
git_hash_ctx c ;
514
513
int object_header_len ;
515
514
int ret ;
515
+ unsigned flags = 0 ;
516
+ void * content ;
517
+ unsigned long size ;
518
+ enum object_type type ;
519
+ struct object_info oi = OBJECT_INFO_INIT ;
520
+
521
+ /*
522
+ * Since `test-gvfs-protocol` is mocking a real GVFS server (cache or
523
+ * main), we don't want a request for a missing object to cause the
524
+ * implicit dynamic fetch mechanism to try to fault-it-in (and cause
525
+ * our call to oid_object_info_extended() to launch another instance
526
+ * of `gvfs-helper` to magically fetch it (which would connect to a
527
+ * new instance of `test-gvfs-protocol`)).
528
+ *
529
+ * Rather, we want a missing object to fail, so we can respond with
530
+ * a 404, for example.
531
+ */
532
+ flags |= OBJECT_INFO_FOR_PREFETCH ;
533
+ flags |= OBJECT_INFO_LOOKUP_REPLACE ;
534
+
535
+ oi .typep = & type ;
536
+ oi .sizep = & size ;
537
+ oi .contentp = & content ;
538
+
539
+ if (oid_object_info_extended (the_repository , oid , & oi , flags )) {
540
+ logerror ("Could not find OID: '%s'" , oid_to_hex (oid ));
541
+ return send_http_error (1 , 404 , "Not Found" , -1 , WR_OK );
542
+ }
543
+
544
+ if (string_list_has_string (& mayhem_list , "http_404" )) {
545
+ logmayhem ("http_404" );
546
+ return send_http_error (1 , 404 , "Not Found" , -1 , WR_MAYHEM );
547
+ }
548
+
549
+ trace2_printf ("%s: OBJECT type=%d len=%ld '%.40s'" , TR2_CAT ,
550
+ type , size , (const char * )content );
516
551
517
552
/*
518
553
* We are blending several somewhat independent concepts here:
@@ -567,13 +602,13 @@ static enum worker_result send_loose_object(const struct object_info *oi,
567
602
/* [1a] */
568
603
object_header_len = 1 + xsnprintf (object_header , MAX_HEADER_LEN ,
569
604
"%s %" PRIuMAX ,
570
- type_name (* oi -> typep ),
571
- (uintmax_t )* oi -> sizep );
605
+ type_name (* oi . typep ),
606
+ (uintmax_t )* oi . sizep );
572
607
573
608
/* [2] */
574
609
the_hash_algo -> init_fn (& c );
575
610
the_hash_algo -> update_fn (& c , object_header , object_header_len );
576
- the_hash_algo -> update_fn (& c , * oi -> contentp , * oi -> sizep );
611
+ the_hash_algo -> update_fn (& c , * oi . contentp , * oi . sizep );
577
612
the_hash_algo -> final_fn (oid_check .hash , & c );
578
613
if (!oideq (oid , & oid_check ))
579
614
BUG ("send_loose_object[2]: invalid construction '%s' '%s'" ,
@@ -593,8 +628,8 @@ static enum worker_result send_loose_object(const struct object_info *oi,
593
628
the_hash_algo -> update_fn (& c , object_header , object_header_len );
594
629
595
630
/* [3, 1b, 5, 6] */
596
- stream .next_in = * oi -> contentp ;
597
- stream .avail_in = * oi -> sizep ;
631
+ stream .next_in = * oi . contentp ;
632
+ stream .avail_in = * oi . sizep ;
598
633
do {
599
634
enum worker_result wr ;
600
635
unsigned char * in0 = stream .next_in ;
@@ -639,25 +674,6 @@ static enum worker_result send_loose_object(const struct object_info *oi,
639
674
static enum worker_result do__gvfs_objects__get (struct req * req )
640
675
{
641
676
struct object_id oid ;
642
- void * content ;
643
- unsigned long size ;
644
- enum object_type type ;
645
- struct object_info oi = OBJECT_INFO_INIT ;
646
- unsigned flags = 0 ;
647
-
648
- /*
649
- * Since `test-gvfs-protocol` is mocking a real GVFS server (cache or
650
- * main), we don't want a request for a missing object to cause the
651
- * implicit dynamic fetch mechanism to try to fault-it-in (and cause
652
- * our call to oid_object_info_extended() to launch another instance
653
- * of `gvfs-helper` to magically fetch it (which would connect to a
654
- * new instance of `test-gvfs-protocol`)).
655
- *
656
- * Rather, we want a missing object to fail, so we can respond with
657
- * a 404, for example.
658
- */
659
- flags |= OBJECT_INFO_FOR_PREFETCH ;
660
- flags |= OBJECT_INFO_LOOKUP_REPLACE ;
661
677
662
678
if (!req -> slash_args .len ||
663
679
get_oid_hex (req -> slash_args .buf , & oid )) {
@@ -668,29 +684,13 @@ static enum worker_result do__gvfs_objects__get(struct req *req)
668
684
669
685
trace2_printf ("%s: GET %s" , TR2_CAT , oid_to_hex (& oid ));
670
686
671
- oi .typep = & type ;
672
- oi .sizep = & size ;
673
- oi .contentp = & content ;
674
-
675
- if (oid_object_info_extended (the_repository , & oid , & oi , flags )) {
676
- logerror ("Could not find OID: '%s'" , oid_to_hex (& oid ));
677
- return send_http_error (1 , 404 , "Not Found" , -1 , WR_OK );
678
- }
679
-
680
- if (string_list_has_string (& mayhem_list , "http_404" )) {
681
- logmayhem ("http_404" );
682
- return send_http_error (1 , 404 , "Not Found" , -1 , WR_MAYHEM );
683
- }
684
-
685
- trace2_printf ("%s: OBJECT type=%d len=%ld '%.40s'" , TR2_CAT ,
686
- type , size , (const char * )content );
687
-
688
- return send_loose_object (& oi , & oid , 1 );
687
+ return send_loose_object (& oid , 1 );
689
688
}
690
689
691
690
static enum worker_result read_json_post_body (
692
691
struct req * req ,
693
- struct oidset * oids )
692
+ struct oidset * oids ,
693
+ int * nr_oids )
694
694
{
695
695
struct object_id oid ;
696
696
struct string_list_item * item ;
@@ -759,7 +759,8 @@ static enum worker_result read_json_post_body(
759
759
760
760
if (get_oid_hex (pstart , & oid ))
761
761
goto could_not_parse_json ;
762
- oidset_insert (oids , & oid );
762
+ if (!oidset_insert (oids , & oid ))
763
+ * nr_oids += 1 ;
763
764
trace2_printf ("%s: POST %s" , TR2_CAT , oid_to_hex (& oid ));
764
765
765
766
/* Eat trailing whitespace after trailing DQUOTE */
@@ -803,16 +804,6 @@ static enum worker_result read_json_post_body(
803
804
*
804
805
* My assumption here is that we're not testing with GBs
805
806
* of data....
806
- *
807
- * Note: The GVFS Protocol POST verb behaves like GET for
808
- * Note: non-commit objects (in that it just returns the
809
- * Note: requested object), but for commit objects POST
810
- * Note: *also* returns all trees referenced by the commit.
811
- * Note:
812
- * Note: Since the goal of this test is to confirm that
813
- * Note: gvfs-helper can request and receive a packfile
814
- * Note: *at all*, I'm not going to blur the issue and
815
- * Note: support the extra semantics for commit objects.
816
807
*/
817
808
static enum worker_result get_packfile_from_oids (
818
809
struct oidset * oids ,
@@ -902,21 +893,99 @@ static enum worker_result send_packfile_from_buffer(const struct strbuf *packfil
902
893
return wr ;
903
894
}
904
895
896
+ /*
897
+ * The GVFS Protocol POST verb behaves like GET for non-commit objects
898
+ * (in that it just returns the requested object), but for commit
899
+ * objects POST *also* returns all trees referenced by the commit.
900
+ *
901
+ * The goal of this test is to confirm that:
902
+ * [] `gvfs-helper post` can request and receive a packfile at all.
903
+ * [] `gvfs-helper post` can handle getting either a packfile or a
904
+ * loose object.
905
+ *
906
+ * Therefore, I'm not going to blur the issue and support the custom
907
+ * semantics for commit objects.
908
+ *
909
+ * If one of the OIDs is a commit, `git pack-objects` will completely
910
+ * walk the trees and blobs for it and we get that for free. This is
911
+ * good enough for our testing.
912
+ *
913
+ * TODO A proper solution would separate the commit objects and do a
914
+ * TODO `rev-list --filter=blobs:none` for them (or use the internal
915
+ * TODO list-objects API) and a regular enumeration for the non-commit
916
+ * TODO objects. And build an new oidset with union of those and then
917
+ * TODO call pack-objects on it instead.
918
+ * TODO
919
+ * TODO But that's too much trouble for now.
920
+ *
921
+ * For now, we just need to know if the post asks for a single object,
922
+ * is it a commit or non-commit. That is sufficient to know whether
923
+ * we should send a packfile or loose object.
924
+ */
925
+ static enum worker_result classify_oids_in_post (
926
+ struct oidset * oids , int nr_oids , int * need_packfile )
927
+ {
928
+ struct oidset_iter iter ;
929
+ struct object_id * oid ;
930
+ enum object_type type ;
931
+ struct object_info oi = OBJECT_INFO_INIT ;
932
+ unsigned flags = 0 ;
933
+
934
+ if (nr_oids > 1 ) {
935
+ * need_packfile = 1 ;
936
+ return WR_OK ;
937
+ }
938
+
939
+ /* disable missing-object faulting */
940
+ flags |= OBJECT_INFO_FOR_PREFETCH ;
941
+ flags |= OBJECT_INFO_LOOKUP_REPLACE ;
942
+
943
+ oi .typep = & type ;
944
+
945
+ oidset_iter_init (oids , & iter );
946
+ while ((oid = oidset_iter_next (& iter ))) {
947
+ if (!oid_object_info_extended (the_repository , oid , & oi , flags ) &&
948
+ type == OBJ_COMMIT ) {
949
+ * need_packfile = 1 ;
950
+ return WR_OK ;
951
+ }
952
+ }
953
+
954
+ * need_packfile = 0 ;
955
+ return WR_OK ;
956
+ }
957
+
905
958
static enum worker_result do__gvfs_objects__post (struct req * req )
906
959
{
907
960
struct oidset oids = OIDSET_INIT ;
908
961
struct strbuf packfile = STRBUF_INIT ;
909
962
enum worker_result wr ;
963
+ int nr_oids = 0 ;
964
+ int need_packfile = 0 ;
910
965
911
- wr = read_json_post_body (req , & oids );
966
+ wr = read_json_post_body (req , & oids , & nr_oids );
912
967
if (wr & WR_STOP_THE_MUSIC )
913
968
goto done ;
914
969
915
- wr = get_packfile_from_oids (& oids , & packfile );
970
+ wr = classify_oids_in_post (& oids , nr_oids , & need_packfile );
916
971
if (wr & WR_STOP_THE_MUSIC )
917
972
goto done ;
918
973
919
- wr = send_packfile_from_buffer (& packfile );
974
+ if (!need_packfile ) {
975
+ struct oidset_iter iter ;
976
+ struct object_id * oid ;
977
+
978
+ oidset_iter_init (& oids , & iter );
979
+ oid = oidset_iter_next (& iter );
980
+
981
+ wr = send_loose_object (oid , 1 );
982
+ } else {
983
+ wr = get_packfile_from_oids (& oids , & packfile );
984
+ if (wr & WR_STOP_THE_MUSIC )
985
+ goto done ;
986
+
987
+ wr = send_packfile_from_buffer (& packfile );
988
+ }
920
989
921
990
done :
922
991
oidset_clear (& oids );
0 commit comments