package archive import ( "bytes" "errors" "fmt" "net/http" "net/url" "strconv" "time" ) func (this *ArchiveServer) lookupSourceByNumericString(slug string) *LogSource { intval, err := strconv.Atoi(slug) if err != nil { return nil } if intval >= 0 && intval < len(this.cfg.Logs) { return &this.cfg.Logs[intval] } return nil } func (this *ArchiveServer) lookupSource(slug string) *LogSource { if src := this.lookupSourceByNumericString(slug); src != nil { return src } for i, ls := range this.cfg.Logs { for _, s := range ls.Slugs { if s == slug { return &this.cfg.Logs[i] } } } return nil // not found } func (this *ArchiveServer) bestSlugFor(ls *LogSource) (string, error) { for i := 0; i < len(this.cfg.Logs); i += 1 { if ls != &this.cfg.Logs[i] { continue } if len(this.cfg.Logs[i].Slugs) > 0 { return this.cfg.Logs[i].Slugs[0], nil // first slug is preferred } else { return fmt.Sprintf(`%d`, i), nil // no slugs present? use numeric log index } } return "", errors.New("Unregistered log source") } func (this *ArchiveServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Header().Set("Server", SERVER_VERSION) if r.Method != "GET" { http.Error(w, "Expected GET", http.StatusMethodNotAllowed) return } if len(r.URL.Path) == 0 { http.Error(w, "Invalid request", http.StatusBadRequest) return } // Handle static assets static, err := Asset(r.URL.Path[1:]) if err == nil { http.ServeContent(w, r, r.URL.Path[1:], this.startup, bytes.NewReader(static)) return } // Handle application routes arc := NewArchiveState(this) if r.URL.Path == `/` { ls := &this.cfg.Logs[0] slug, _ := this.bestSlugFor(ls) dt := ls.LatestDate() http.Redirect(w, r, fmt.Sprintf(`/%s/%d/%d`, slug, dt.Year, dt.Month), http.StatusTemporaryRedirect) } else if len(r.URL.Query().Get("y")) > 0 || len(r.URL.Query().Get("q")) > 0 || len(r.URL.Query().Get("h")) > 0 { this.legacyRoute(w, r) } else if r.URL.Path == `/download` { this.serveDownload(w) } else if matches := this.rxViewRoot.FindStringSubmatch(r.URL.Path); len(matches) > 0 { if ls := this.lookupSource(matches[1]); ls != nil { arc.selectSource(ls, matches[1]) y, _ := strconv.Atoi(matches[2]) m, _ := strconv.Atoi(matches[3]) arc.ym = YearMonth{Year: y, Month: time.Month(m)} // 1-based months arc.renderView(w) } else { arc.renderError(w, fmt.Sprintf("Unknown source '%s'", matches[1])) } } else if matches := this.rxViewPage.FindStringSubmatch(r.URL.Path); len(matches) > 0 { if ls := this.lookupSource(matches[1]); ls != nil { arc.selectSource(ls, matches[1]) y, _ := strconv.Atoi(matches[2]) m, _ := strconv.Atoi(matches[3]) arc.ym = YearMonth{Year: y, Month: time.Month(m)} // 1-based months arc.page, _ = strconv.Atoi(matches[4]) arc.renderView(w) } else { arc.renderError(w, fmt.Sprintf("Unknown source '%s'", matches[1])) } } else if matches := this.rxSearch.FindStringSubmatch(r.URL.Path); len(matches) > 0 { if ls := this.lookupSource(matches[1]); ls != nil { arc.selectSource(ls, matches[1]) arc.query, _ = url.QueryUnescape(matches[2]) arc.queryIsRegex = false arc.renderSearch(w) } else { arc.renderError(w, fmt.Sprintf("Unknown source '%s'", matches[1])) } } else if matches := this.rxSearchRx.FindStringSubmatch(r.URL.Path); len(matches) > 0 { if ls := this.lookupSource(matches[1]); ls != nil { arc.selectSource(ls, matches[1]) arc.query, _ = url.QueryUnescape(matches[2]) arc.queryIsRegex = true arc.renderSearch(w) } else { arc.renderError(w, fmt.Sprintf("Unknown source '%s'", matches[1])) } } else { arc.renderError(w, "Unknown route.") } } func (this *ArchiveServer) legacyRoute(w http.ResponseWriter, r *http.Request) { u := URLHelper{w, r} hubid := 0 if u.hasGet("h") { hubid = u.intval(u.get("h")) } // if u.hasGet("q") { if u.hasGet("rx") { u.redirectf(`/%d/rx/%s`, hubid, url.QueryEscape(u.get("q"))) } else { u.redirectf(`/%d/search/%s`, hubid, url.QueryEscape(u.get("q"))) } } else if u.hasGet("y") && u.hasGet("m") { year := u.intval(u.get("y")) month := u.intval(u.get("m")) if u.hasGet("p") { u.redirectf(`/%d/%d/%d/page-%d`, hubid, year, month, u.intval(u.get("p"))) } else { u.redirectf(`/%d/%d/%d`, hubid, year, month) } } else { if hi := this.lookupSourceByNumericString(u.get("h")); hi != nil { currentDate := hi.LatestDate() u.redirectf(`/%d/%d/%d`, hubid, currentDate.Year, currentDate.Month) } else { u.redirectf(`/`) } } }