@@ -491,8 +491,7 @@ static enum worker_result do__gvfs_config__get(struct req *req)
491
491
* write_object_file_prepare()
492
492
* write_loose_object()
493
493
*/
494
- static enum worker_result send_loose_object (const struct object_info * oi ,
495
- const struct object_id * oid ,
494
+ static enum worker_result send_loose_object (const struct object_id * oid ,
496
495
int fd )
497
496
{
498
497
#define MAX_HEADER_LEN 32
@@ -505,6 +504,42 @@ static enum worker_result send_loose_object(const struct object_info *oi,
505
504
git_hash_ctx c ;
506
505
int object_header_len ;
507
506
int ret ;
507
+ unsigned flags = 0 ;
508
+ void * content ;
509
+ unsigned long size ;
510
+ enum object_type type ;
511
+ struct object_info oi = OBJECT_INFO_INIT ;
512
+
513
+ /*
514
+ * Since `test-gvfs-protocol` is mocking a real GVFS server (cache or
515
+ * main), we don't want a request for a missing object to cause the
516
+ * implicit dynamic fetch mechanism to try to fault-it-in (and cause
517
+ * our call to oid_object_info_extended() to launch another instance
518
+ * of `gvfs-helper` to magically fetch it (which would connect to a
519
+ * new instance of `test-gvfs-protocol`)).
520
+ *
521
+ * Rather, we want a missing object to fail, so we can respond with
522
+ * a 404, for example.
523
+ */
524
+ flags |= OBJECT_INFO_FOR_PREFETCH ;
525
+ flags |= OBJECT_INFO_LOOKUP_REPLACE ;
526
+
527
+ oi .typep = & type ;
528
+ oi .sizep = & size ;
529
+ oi .contentp = & content ;
530
+
531
+ if (oid_object_info_extended (the_repository , oid , & oi , flags )) {
532
+ logerror ("Could not find OID: '%s'" , oid_to_hex (oid ));
533
+ return send_http_error (1 , 404 , "Not Found" , -1 , WR_OK );
534
+ }
535
+
536
+ if (string_list_has_string (& mayhem_list , "http_404" )) {
537
+ logmayhem ("http_404" );
538
+ return send_http_error (1 , 404 , "Not Found" , -1 , WR_MAYHEM );
539
+ }
540
+
541
+ trace2_printf ("%s: OBJECT type=%d len=%ld '%.40s'" , TR2_CAT ,
542
+ type , size , (const char * )content );
508
543
509
544
/*
510
545
* We are blending several somewhat independent concepts here:
@@ -559,13 +594,13 @@ static enum worker_result send_loose_object(const struct object_info *oi,
559
594
/* [1a] */
560
595
object_header_len = 1 + xsnprintf (object_header , MAX_HEADER_LEN ,
561
596
"%s %" PRIuMAX ,
562
- type_name (* oi -> typep ),
563
- (uintmax_t )* oi -> sizep );
597
+ type_name (* oi . typep ),
598
+ (uintmax_t )* oi . sizep );
564
599
565
600
/* [2] */
566
601
the_hash_algo -> init_fn (& c );
567
602
the_hash_algo -> update_fn (& c , object_header , object_header_len );
568
- the_hash_algo -> update_fn (& c , * oi -> contentp , * oi -> sizep );
603
+ the_hash_algo -> update_fn (& c , * oi . contentp , * oi . sizep );
569
604
the_hash_algo -> final_fn (oid_check .hash , & c );
570
605
if (!oideq (oid , & oid_check ))
571
606
BUG ("send_loose_object[2]: invalid construction '%s' '%s'" ,
@@ -585,8 +620,8 @@ static enum worker_result send_loose_object(const struct object_info *oi,
585
620
the_hash_algo -> update_fn (& c , object_header , object_header_len );
586
621
587
622
/* [3, 1b, 5, 6] */
588
- stream .next_in = * oi -> contentp ;
589
- stream .avail_in = * oi -> sizep ;
623
+ stream .next_in = * oi . contentp ;
624
+ stream .avail_in = * oi . sizep ;
590
625
do {
591
626
enum worker_result wr ;
592
627
unsigned char * in0 = stream .next_in ;
@@ -631,25 +666,6 @@ static enum worker_result send_loose_object(const struct object_info *oi,
631
666
static enum worker_result do__gvfs_objects__get (struct req * req )
632
667
{
633
668
struct object_id oid ;
634
- void * content ;
635
- unsigned long size ;
636
- enum object_type type ;
637
- struct object_info oi = OBJECT_INFO_INIT ;
638
- unsigned flags = 0 ;
639
-
640
- /*
641
- * Since `test-gvfs-protocol` is mocking a real GVFS server (cache or
642
- * main), we don't want a request for a missing object to cause the
643
- * implicit dynamic fetch mechanism to try to fault-it-in (and cause
644
- * our call to oid_object_info_extended() to launch another instance
645
- * of `gvfs-helper` to magically fetch it (which would connect to a
646
- * new instance of `test-gvfs-protocol`)).
647
- *
648
- * Rather, we want a missing object to fail, so we can respond with
649
- * a 404, for example.
650
- */
651
- flags |= OBJECT_INFO_FOR_PREFETCH ;
652
- flags |= OBJECT_INFO_LOOKUP_REPLACE ;
653
669
654
670
if (!req -> slash_args .len ||
655
671
get_oid_hex (req -> slash_args .buf , & oid )) {
@@ -660,29 +676,13 @@ static enum worker_result do__gvfs_objects__get(struct req *req)
660
676
661
677
trace2_printf ("%s: GET %s" , TR2_CAT , oid_to_hex (& oid ));
662
678
663
- oi .typep = & type ;
664
- oi .sizep = & size ;
665
- oi .contentp = & content ;
666
-
667
- if (oid_object_info_extended (the_repository , & oid , & oi , flags )) {
668
- logerror ("Could not find OID: '%s'" , oid_to_hex (& oid ));
669
- return send_http_error (1 , 404 , "Not Found" , -1 , WR_OK );
670
- }
671
-
672
- if (string_list_has_string (& mayhem_list , "http_404" )) {
673
- logmayhem ("http_404" );
674
- return send_http_error (1 , 404 , "Not Found" , -1 , WR_MAYHEM );
675
- }
676
-
677
- trace2_printf ("%s: OBJECT type=%d len=%ld '%.40s'" , TR2_CAT ,
678
- type , size , (const char * )content );
679
-
680
- return send_loose_object (& oi , & oid , 1 );
679
+ return send_loose_object (& oid , 1 );
681
680
}
682
681
683
682
static enum worker_result read_json_post_body (
684
683
struct req * req ,
685
- struct oidset * oids )
684
+ struct oidset * oids ,
685
+ int * nr_oids )
686
686
{
687
687
struct object_id oid ;
688
688
struct string_list_item * item ;
@@ -751,7 +751,8 @@ static enum worker_result read_json_post_body(
751
751
752
752
if (get_oid_hex (pstart , & oid ))
753
753
goto could_not_parse_json ;
754
- oidset_insert (oids , & oid );
754
+ if (!oidset_insert (oids , & oid ))
755
+ * nr_oids += 1 ;
755
756
trace2_printf ("%s: POST %s" , TR2_CAT , oid_to_hex (& oid ));
756
757
757
758
/* Eat trailing whitespace after trailing DQUOTE */
@@ -795,16 +796,6 @@ static enum worker_result read_json_post_body(
795
796
*
796
797
* My assumption here is that we're not testing with GBs
797
798
* of data....
798
- *
799
- * Note: The GVFS Protocol POST verb behaves like GET for
800
- * Note: non-commit objects (in that it just returns the
801
- * Note: requested object), but for commit objects POST
802
- * Note: *also* returns all trees referenced by the commit.
803
- * Note:
804
- * Note: Since the goal of this test is to confirm that
805
- * Note: gvfs-helper can request and receive a packfile
806
- * Note: *at all*, I'm not going to blur the issue and
807
- * Note: support the extra semantics for commit objects.
808
799
*/
809
800
static enum worker_result get_packfile_from_oids (
810
801
struct oidset * oids ,
@@ -894,21 +885,99 @@ static enum worker_result send_packfile_from_buffer(const struct strbuf *packfil
894
885
return wr ;
895
886
}
896
887
888
+ /*
889
+ * The GVFS Protocol POST verb behaves like GET for non-commit objects
890
+ * (in that it just returns the requested object), but for commit
891
+ * objects POST *also* returns all trees referenced by the commit.
892
+ *
893
+ * The goal of this test is to confirm that:
894
+ * [] `gvfs-helper post` can request and receive a packfile at all.
895
+ * [] `gvfs-helper post` can handle getting either a packfile or a
896
+ * loose object.
897
+ *
898
+ * Therefore, I'm not going to blur the issue and support the custom
899
+ * semantics for commit objects.
900
+ *
901
+ * If one of the OIDs is a commit, `git pack-objects` will completely
902
+ * walk the trees and blobs for it and we get that for free. This is
903
+ * good enough for our testing.
904
+ *
905
+ * TODO A proper solution would separate the commit objects and do a
906
+ * TODO `rev-list --filter=blobs:none` for them (or use the internal
907
+ * TODO list-objects API) and a regular enumeration for the non-commit
908
+ * TODO objects. And build an new oidset with union of those and then
909
+ * TODO call pack-objects on it instead.
910
+ * TODO
911
+ * TODO But that's too much trouble for now.
912
+ *
913
+ * For now, we just need to know if the post asks for a single object,
914
+ * is it a commit or non-commit. That is sufficient to know whether
915
+ * we should send a packfile or loose object.
916
+ */
917
+ static enum worker_result classify_oids_in_post (
918
+ struct oidset * oids , int nr_oids , int * need_packfile )
919
+ {
920
+ struct oidset_iter iter ;
921
+ struct object_id * oid ;
922
+ enum object_type type ;
923
+ struct object_info oi = OBJECT_INFO_INIT ;
924
+ unsigned flags = 0 ;
925
+
926
+ if (nr_oids > 1 ) {
927
+ * need_packfile = 1 ;
928
+ return WR_OK ;
929
+ }
930
+
931
+ /* disable missing-object faulting */
932
+ flags |= OBJECT_INFO_FOR_PREFETCH ;
933
+ flags |= OBJECT_INFO_LOOKUP_REPLACE ;
934
+
935
+ oi .typep = & type ;
936
+
937
+ oidset_iter_init (oids , & iter );
938
+ while ((oid = oidset_iter_next (& iter ))) {
939
+ if (!oid_object_info_extended (the_repository , oid , & oi , flags ) &&
940
+ type == OBJ_COMMIT ) {
941
+ * need_packfile = 1 ;
942
+ return WR_OK ;
943
+ }
944
+ }
945
+
946
+ * need_packfile = 0 ;
947
+ return WR_OK ;
948
+ }
949
+
897
950
static enum worker_result do__gvfs_objects__post (struct req * req )
898
951
{
899
952
struct oidset oids = OIDSET_INIT ;
900
953
struct strbuf packfile = STRBUF_INIT ;
901
954
enum worker_result wr ;
955
+ int nr_oids = 0 ;
956
+ int need_packfile = 0 ;
902
957
903
- wr = read_json_post_body (req , & oids );
958
+ wr = read_json_post_body (req , & oids , & nr_oids );
904
959
if (wr & WR_STOP_THE_MUSIC )
905
960
goto done ;
906
961
907
- wr = get_packfile_from_oids (& oids , & packfile );
962
+ wr = classify_oids_in_post (& oids , nr_oids , & need_packfile );
908
963
if (wr & WR_STOP_THE_MUSIC )
909
964
goto done ;
910
965
911
- wr = send_packfile_from_buffer (& packfile );
966
+ if (!need_packfile ) {
967
+ struct oidset_iter iter ;
968
+ struct object_id * oid ;
969
+
970
+ oidset_iter_init (& oids , & iter );
971
+ oid = oidset_iter_next (& iter );
972
+
973
+ wr = send_loose_object (oid , 1 );
974
+ } else {
975
+ wr = get_packfile_from_oids (& oids , & packfile );
976
+ if (wr & WR_STOP_THE_MUSIC )
977
+ goto done ;
978
+
979
+ wr = send_packfile_from_buffer (& packfile );
980
+ }
912
981
913
982
done :
914
983
oidset_clear (& oids );
0 commit comments