+1
README.md
+1
README.md
···
70
- The `POST` method requires an `application/json` body containing a Forgejo/Gitea/Gogs/GitHub webhook event payload. Requests where the `ref` key contains anything other than `refs/heads/pages` are ignored, and only the `pages` branch is used. The `repository.clone_url` key contains a repository URL to be shallowly cloned.
71
- If the received contents is empty, performs the same action as `DELETE`.
72
* In response to a `DELETE` request, the server unpublishes a site. The URL of the request must be the root URL of the site that is being unpublished. Site data remains stored for an indeterminate period of time, but becomes completely inaccessible.
73
* All updates to site content are atomic (subject to consistency guarantees of the storage backend). That is, there is an instantaneous moment during an update before which the server will return the old content and after which it will return the new content.
74
* Files with a certain name, when placed in the root of a site, have special functions:
75
- [Netlify `_redirects`][_redirects] file can be used to specify HTTP redirect and rewrite rules. The _git-pages_ implementation currently does not support placeholders, query parameters, or conditions, and may differ from Netlify in other minor ways. If you find that a supported `_redirects` file feature does not work the same as on Netlify, please file an issue. (Note that _git-pages_ does not perform URL normalization; `/foo` and `/foo/` are *not* the same, unlike with Netlify.)
···
70
- The `POST` method requires an `application/json` body containing a Forgejo/Gitea/Gogs/GitHub webhook event payload. Requests where the `ref` key contains anything other than `refs/heads/pages` are ignored, and only the `pages` branch is used. The `repository.clone_url` key contains a repository URL to be shallowly cloned.
71
- If the received contents is empty, performs the same action as `DELETE`.
72
* In response to a `DELETE` request, the server unpublishes a site. The URL of the request must be the root URL of the site that is being unpublished. Site data remains stored for an indeterminate period of time, but becomes completely inaccessible.
73
+
* If a `Dry-Run: yes` header is provided with a `PUT`, `DELETE`, or `POST` request, only the authorization checks are run; no destructive updates are made. Note that this functionality was added in _git-pages_ v0.2.0.
74
* All updates to site content are atomic (subject to consistency guarantees of the storage backend). That is, there is an instantaneous moment during an update before which the server will return the old content and after which it will return the new content.
75
* Files with a certain name, when placed in the root of a site, have special functions:
76
- [Netlify `_redirects`][_redirects] file can be used to specify HTTP redirect and rewrite rules. The _git-pages_ implementation currently does not support placeholders, query parameters, or conditions, and may differ from Netlify in other minor ways. If you find that a supported `_redirects` file feature does not work the same as on Netlify, please file an issue. (Note that _git-pages_ does not perform URL normalization; `/foo` and `/foo/` are *not* the same, unlike with Netlify.)
+30
-7
src/pages.go
+30
-7
src/pages.go
···
405
return nil
406
}
407
408
func putPage(w http.ResponseWriter, r *http.Request) error {
409
var result UpdateResult
410
···
424
defer cancel()
425
426
contentType := getMediaType(r.Header.Get("Content-Type"))
427
-
428
-
if contentType == "application/x-www-form-urlencoded" {
429
auth, err := AuthorizeUpdateFromRepository(r)
430
if err != nil {
431
return err
···
450
return err
451
}
452
453
result = UpdateFromRepository(updateCtx, webRoot, repoURL, branch)
454
-
} else {
455
_, err := AuthorizeUpdateFromArchive(r)
456
if err != nil {
457
return err
458
}
459
460
// request body contains archive
···
518
return err
519
}
520
521
err = backend.DeleteManifest(r.Context(), makeWebRoot(host, projectName))
522
if err != nil {
523
w.WriteHeader(http.StatusInternalServerError)
···
618
return err
619
}
620
621
resultChan := make(chan UpdateResult)
622
go func(ctx context.Context) {
623
ctx, cancel := context.WithTimeout(ctx, time.Duration(config.Limits.UpdateTimeout))
···
645
w.WriteHeader(http.StatusGatewayTimeout)
646
fmt.Fprintln(w, "update timeout")
647
case UpdateNoChange:
648
-
w.WriteHeader(http.StatusOK)
649
fmt.Fprintln(w, "unchanged")
650
case UpdateCreated:
651
-
w.WriteHeader(http.StatusOK)
652
fmt.Fprintln(w, "created")
653
case UpdateReplaced:
654
-
w.WriteHeader(http.StatusOK)
655
fmt.Fprintln(w, "replaced")
656
case UpdateDeleted:
657
-
w.WriteHeader(http.StatusOK)
658
fmt.Fprintln(w, "deleted")
659
}
660
if result.manifest != nil {
···
405
return nil
406
}
407
408
+
func checkDryRun(w http.ResponseWriter, r *http.Request) bool {
409
+
// "Dry run" requests are used to non-destructively check if the request would have
410
+
// successfully been authorized.
411
+
if r.Header.Get("Dry-Run") != "" {
412
+
fmt.Fprintln(w, "dry-run ok")
413
+
return true
414
+
}
415
+
return false
416
+
}
417
+
418
func putPage(w http.ResponseWriter, r *http.Request) error {
419
var result UpdateResult
420
···
434
defer cancel()
435
436
contentType := getMediaType(r.Header.Get("Content-Type"))
437
+
switch contentType {
438
+
case "application/x-www-form-urlencoded":
439
auth, err := AuthorizeUpdateFromRepository(r)
440
if err != nil {
441
return err
···
460
return err
461
}
462
463
+
if checkDryRun(w, r) {
464
+
return nil
465
+
}
466
+
467
result = UpdateFromRepository(updateCtx, webRoot, repoURL, branch)
468
+
469
+
default:
470
_, err := AuthorizeUpdateFromArchive(r)
471
if err != nil {
472
return err
473
+
}
474
+
475
+
if checkDryRun(w, r) {
476
+
return nil
477
}
478
479
// request body contains archive
···
537
return err
538
}
539
540
+
if checkDryRun(w, r) {
541
+
return nil
542
+
}
543
+
544
err = backend.DeleteManifest(r.Context(), makeWebRoot(host, projectName))
545
if err != nil {
546
w.WriteHeader(http.StatusInternalServerError)
···
641
return err
642
}
643
644
+
if checkDryRun(w, r) {
645
+
return nil
646
+
}
647
+
648
resultChan := make(chan UpdateResult)
649
go func(ctx context.Context) {
650
ctx, cancel := context.WithTimeout(ctx, time.Duration(config.Limits.UpdateTimeout))
···
672
w.WriteHeader(http.StatusGatewayTimeout)
673
fmt.Fprintln(w, "update timeout")
674
case UpdateNoChange:
675
fmt.Fprintln(w, "unchanged")
676
case UpdateCreated:
677
fmt.Fprintln(w, "created")
678
case UpdateReplaced:
679
fmt.Fprintln(w, "replaced")
680
case UpdateDeleted:
681
fmt.Fprintln(w, "deleted")
682
}
683
if result.manifest != nil {