(w http.ResponseWriter, r *http.Request)
| 479 | } |
| 480 | |
| 481 | func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request) (status int, err error) { |
| 482 | hdr := r.Header.Get("Destination") |
| 483 | if hdr == "" { |
| 484 | return http.StatusBadRequest, errInvalidDestination |
| 485 | } |
| 486 | u, err := url.Parse(hdr) |
| 487 | if err != nil { |
| 488 | return http.StatusBadRequest, errInvalidDestination |
| 489 | } |
| 490 | if u.Host != "" && u.Host != r.Host { |
| 491 | return http.StatusBadGateway, errInvalidDestination |
| 492 | } |
| 493 | |
| 494 | src, status, err := h.stripPrefix(r.URL.Path) |
| 495 | if err != nil { |
| 496 | return status, err |
| 497 | } |
| 498 | |
| 499 | dst, status, err := h.stripPrefix(u.Path) |
| 500 | if err != nil { |
| 501 | return status, err |
| 502 | } |
| 503 | |
| 504 | if dst == "" { |
| 505 | return http.StatusBadGateway, errInvalidDestination |
| 506 | } |
| 507 | if dst == src { |
| 508 | return http.StatusForbidden, errDestinationEqualsSource |
| 509 | } |
| 510 | |
| 511 | ctx := r.Context() |
| 512 | user := ctx.Value(conf.UserKey).(*model.User) |
| 513 | src, err = user.JoinPath(src) |
| 514 | if err != nil { |
| 515 | return http.StatusForbidden, err |
| 516 | } |
| 517 | dst, err = user.JoinPath(dst) |
| 518 | if err != nil { |
| 519 | return http.StatusForbidden, err |
| 520 | } |
| 521 | |
| 522 | if r.Method == "COPY" { |
| 523 | // Section 7.5.1 says that a COPY only needs to lock the destination, |
| 524 | // not both destination and source. Strictly speaking, this is racy, |
| 525 | // even though a COPY doesn't modify the source, if a concurrent |
| 526 | // operation modifies the source. However, the litmus test explicitly |
| 527 | // checks that COPYing a locked-by-another source is OK. |
| 528 | release, status, err := h.confirmLocks(r, "", dst) |
| 529 | if err != nil { |
| 530 | return status, err |
| 531 | } |
| 532 | defer release() |
| 533 | |
| 534 | // Section 9.8.3 says that "The COPY method on a collection without a Depth |
| 535 | // header must act as if a Depth header with value "infinity" was included". |
| 536 | depth := infiniteDepth |
| 537 | if hdr := r.Header.Get("Depth"); hdr != "" { |
| 538 | depth = parseDepth(hdr) |
no test coverage detected