(w http.ResponseWriter, r *http.Request)
| 508 | } |
| 509 | |
| 510 | func serveGo(w http.ResponseWriter, r *http.Request) { |
| 511 | if r.URL.Path == "/" { |
| 512 | switch r.Method { |
| 513 | case "GET": |
| 514 | serveHome(w, r, "") |
| 515 | case "POST": |
| 516 | serveSave(w, r) |
| 517 | } |
| 518 | return |
| 519 | } |
| 520 | |
| 521 | short, remainder, _ := strings.Cut(strings.TrimPrefix(r.URL.Path, "/"), "/") |
| 522 | |
| 523 | // redirect {name}+ links to /.detail/{name} |
| 524 | if strings.HasSuffix(short, "+") { |
| 525 | http.Redirect(w, r, "/.detail/"+strings.TrimSuffix(short, "+"), http.StatusFound) |
| 526 | return |
| 527 | } |
| 528 | |
| 529 | link, err := db.Load(short) |
| 530 | if errors.Is(err, fs.ErrNotExist) { |
| 531 | w.WriteHeader(http.StatusNotFound) |
| 532 | serveHome(w, r, short) |
| 533 | return |
| 534 | } |
| 535 | if err != nil { |
| 536 | log.Printf("serving %q: %v", short, err) |
| 537 | http.Error(w, err.Error(), http.StatusInternalServerError) |
| 538 | return |
| 539 | } |
| 540 | |
| 541 | stats.mu.Lock() |
| 542 | if stats.clicks == nil { |
| 543 | stats.clicks = make(ClickStats) |
| 544 | } |
| 545 | stats.clicks[link.Short]++ |
| 546 | if stats.dirty == nil { |
| 547 | stats.dirty = make(ClickStats) |
| 548 | } |
| 549 | stats.dirty[link.Short]++ |
| 550 | stats.mu.Unlock() |
| 551 | |
| 552 | cu, _ := currentUser(r) |
| 553 | env := expandEnv{Now: time.Now().UTC(), Path: remainder, user: cu.login, query: r.URL.Query()} |
| 554 | target, err := expandLink(link.Long, env) |
| 555 | if err != nil { |
| 556 | log.Printf("expanding %q: %v", link.Long, err) |
| 557 | if errors.Is(err, errNoUser) { |
| 558 | http.Error(w, "link requires a valid user", http.StatusUnauthorized) |
| 559 | return |
| 560 | } |
| 561 | http.Error(w, err.Error(), http.StatusInternalServerError) |
| 562 | return |
| 563 | } |
| 564 | |
| 565 | // http.Redirect always cleans the redirect URL, which we don't always want. |
| 566 | // Instead, manually set status and Location header. |
| 567 | w.Header().Set("Location", target.String()) |
no test coverage detected