package main import ( "bufio" "fmt" "html/template" "net/http" "net/http/cgi" "os" "os/exec" "strings" "time" ) type Result struct { Name string Version string URL string Suite string } type ResultPage struct { Query string Release string NumResults int Time string Results []Result } var resTempl = ` <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" type="text/css" href="./search.css" /> <title>Devuan Package information</title> <style type="text/css"> code {font-weight: normal; margin: 0 0px; padding: 0px 0px; border: 1px solid #ffffff; font-size: 95%; } </style> <body> <div class="nav"> <div class="leftfl"> <a href="https://pkginfo.devuan.org" title="Devuan Package Information"> <span>Home</span></a> <span class="separator">|</span> <a href="https://devuan.org" title="Devuan website"> <span>Devuan</span></a> <span class="separator">|</span> <a href="https://git.devuan.org" title="Devuan gitlab"> <span>Git</span></a> <span class="separator">|</span> <a href="https://devuan.org" title="Devuan BTS"> <span>BTS</span></a> <span class="separator">|</span> <a href="https://dev1galaxy.org" title="dev1galaxy forum"> <span>Forum</span></a> <span class="separator">|</span> <a href="https://popcon.devuan.org" title="Popularity Context"> <span>Popcon</span></a> </div> <div class="rightfl-do"> <a title="Please support Devuan development" class="button-do" href="https://devuan.org/os/donate">donate now!</a> </div> <div class="rightfl-dl"> <a title="Download Devuan" class="button-dl" href="https://files.devuan.org/">download</a> </div> </div> <div class="wrap"> <h1>Devuan Package information</h1> <form method="GET" action="/cgi-bin/d1pkgweb-query"> Search Devuan Packages for: <input type="text" name="search"/> in release <select name="release"> <option value="jessie">Jessie 1.0.0 (oldstable)</option> <option value="ascii" selected>Ascii 2.0.0 (stable) </option> <option value="beowulf" >Beowulf (testing)</option> <option value="ceres" >Ceres (unstable)</option> <option value="experimental" >Experimental</option> <option value="any" >Any</option> </select> <input type="submit" value="Go!"/> </form> <h1>{{.NumResults}} results for <b>"{{.Query}}"</b> in {{.Release}} (in {{.Time}}) </h1> <ul class="res_list"> {{range .Results}} <li class="res_item"> <a href="{{.URL}}">[{{.Suite}}] {{.Name}}-{{.Version}}</a> </li> {{end}} </div> </div> <p style="margin-top:0px; margin-bottom:20px ; text-align: center;"> This site is a cookie-free zone</p> <div class="foot"> <p id="copyright" style="white-space: nowrap;"> Copyright (c) 2014-2018 <a href="https://www.dyne.org" data-rel="fiscal sponsor" title="Learn about our fiscal sponsor">Dyne.org foundation</a> <span></span> <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/" title="This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.">CC-BY-SA 4.0 international</a></p> <p class="trademarks"> Devuan is a registered trademark of the Dyne.org foundation.</p> <p class="trademarks" style="margin-top: -15px;"> Debian is a registered trademark of Software in the Public Interest, Inc. Linux is a registered trademark of Linus Torvalds.</p> </div> </body> </html> ` var releaseMap = map[string]string{ "jessie": "index_jessie.txt", "ascii": "index_ascii.txt", "beowulf": "index_beowulf.txt", "ceres": "index_ceres.txt", "experimental": "index_experimental.txt", "any": "index.txt"} func printError(errCode int, errMsg string) { fmt.Printf("Status:%d %s\r\n", errCode, errMsg) fmt.Printf("Content-Type: text/plain\r\n") fmt.Printf("\r\n%s\r\n", errMsg) } func parseLines(s string) []Result { results := make([]Result, 0, 10) scanner := bufio.NewScanner(strings.NewReader(s)) for scanner.Scan() { URL := scanner.Text() URLParts := strings.Split(URL, "/")[1:] pkgNameVer := strings.Split(URLParts[len(URLParts)-1], ".html")[0] Name := strings.Split(pkgNameVer, "_")[0] Version := strings.Split(pkgNameVer, "_")[1] Suite := URLParts[2] results = append(results, Result{URL: URL, Name: Name, Version: Version, Suite: Suite}) } //fmt.Printf("len(results): %d\n", resSize) return results } func pipeComands(commands []*exec.Cmd) ([]byte, error) { for i, command := range commands[:len(commands)-1] { out, err := command.StdoutPipe() if err != nil { return nil, err } command.Start() commands[i+1].Stdin = out } final, err := commands[len(commands)-1].Output() if err != nil { return nil, err } return final, nil } func getResults(req http.Request) (ResultPage, error) { var res ResultPage var release string req.ParseForm() searchQuery := req.Form["search"] if len(searchQuery) < 1 { printError(503, fmt.Sprintf("Something went wrong in parsing query...\r\n%s\r\n", req.Form)) os.Exit(0) } res.Query = searchQuery[0] QueryTerms := strings.Split(res.Query, " ") selectedRelease := req.Form["release"] if len(selectedRelease) < 1 { release = "any" } else { release = selectedRelease[0] } res.Release = release fmt.Printf("QueryTerms: %s\n", QueryTerms) startTime := time.Now() commands := make([]*exec.Cmd, 0) cmd := "grep" args := []string{QueryTerms[0], releaseMap[release]} commands = append(commands, exec.Command(cmd, args...)) for _, word := range QueryTerms[1:] { args = []string{word} fmt.Printf("word: %s\r\n", word) commands = append(commands, exec.Command(cmd, args...)) } //if cmdOut, err := exec.Command(cmd, args...).Output(); err != nil { if cmdOut, err := pipeComands(commands); err != nil { fmt.Printf("error executing command: %s", err) res.Time = fmt.Sprintf("%s", time.Since(startTime)) return res, nil } else { res.Results = parseLines(string(cmdOut[:len(cmdOut)])) res.NumResults = len(res.Results) res.Time = fmt.Sprintf("%s", time.Since(startTime)) } return res, nil } func printResults(results ResultPage) { t, err := template.New("webpage").Parse(resTempl) if err != nil { printError(502, "Something went wrong...") return } fmt.Printf("Status: 200 OK\r\n") fmt.Printf("Content-Type: text/html\r\n") t.Execute(os.Stdout, results) } func main() { var req *http.Request var err error req, err = cgi.Request() if err != nil { printError(500, "cannot get requested resource"+err.Error()) return } res, err := getResults(*req) if err != nil { printError(404, fmt.Sprintf("%s", err)) } else { printResults(res) } }