diff --git a/README.md b/README.md index 122bde1..11fb8ba 100644 --- a/README.md +++ b/README.md @@ -57,11 +57,16 @@ logs.) * `log`: a log file, with lines separated by newline characters. Multiple log files can be included by including several `log` parts. + If the log is uploaded with a filename `name.ext`, where `name` contains only + alphanumerics, `.`, `-` or `_`, and `ext` is one of `log` or `txt`, then the + file saved to disk is based on that. Otherwise, a suitable name is + constructed. + If using the JSON upload encoding, the request object should instead include a single `logs` field, which is an array of objects with the following fields: - * `id`: textual identifier for the logs. Currently ignored. + * `id`: textual identifier for the logs. Used as the filename, as above. * `lines`: log data. Newlines should be encoded as `\n`, as normal in JSON). * `compressed-log`: a gzipped logfile. Decompressed and then treated the same as diff --git a/src/github.com/matrix-org/rageshake/submit.go b/src/github.com/matrix-org/rageshake/submit.go index 461c150..8af6ebd 100644 --- a/src/github.com/matrix-org/rageshake/submit.go +++ b/src/github.com/matrix-org/rageshake/submit.go @@ -189,7 +189,7 @@ func parseJSONRequest(w http.ResponseWriter, req *http.Request, reportDir string for i, log := range p.Logs { buf := bytes.NewBufferString(log.Lines) - leafName, err := saveLogPart(i, buf, reportDir) + leafName, err := saveLogPart(i, log.ID, buf, reportDir) if err != nil { return nil, err } @@ -286,7 +286,7 @@ func parseFormPart(part *multipart.Part, p *parsedPayload, reportDir string) err } if field == "log" || field == "compressed-log" { - leafName, err := saveLogPart(len(p.Logs), partReader, reportDir) + leafName, err := saveLogPart(len(p.Logs), part.FileName(), partReader, reportDir) if err != nil { return err } @@ -359,11 +359,27 @@ func saveFormPart(leafName string, reader io.Reader, reportDir string) (string, return leafName, nil } +// we require a sensible extension, and don't allow the filename to start with +// '.' +var logRegexp = regexp.MustCompile(`^[a-zA-Z0-9_-][a-zA-Z0-9_.-]*\.(log|txt)$`) + // saveLogPart saves a log upload to the report directory. // // Returns the leafname of the saved file. -func saveLogPart(logNum int, reader io.Reader, reportDir string) (string, error) { - leafName := fmt.Sprintf("logs-%04d.log.gz", logNum) +func saveLogPart(logNum int, filename string, reader io.Reader, reportDir string) (string, error) { + // pick a name to save the log file with. + // + // some clients use sensible names (foo.N.log), which we preserve. For + // others, we just make up a filename. + // + // Either way, we need to append .gz, because we're compressing it. + var leafName string + if logRegexp.MatchString(filename) { + leafName = filename + ".gz" + } else { + leafName = fmt.Sprintf("logs-%04d.log.gz", logNum) + } + fullname := filepath.Join(reportDir, leafName) f, err := os.Create(fullname) diff --git a/src/github.com/matrix-org/rageshake/submit_test.go b/src/github.com/matrix-org/rageshake/submit_test.go index 31ce798..db4c895 100644 --- a/src/github.com/matrix-org/rageshake/submit_test.go +++ b/src/github.com/matrix-org/rageshake/submit_test.go @@ -112,7 +112,7 @@ func TestMultipartUpload(t *testing.T) { // check logs uploaded correctly checkUploadedFile(t, reportDir, "logs-0000.log.gz", true, "log\nlog\nlog") - checkUploadedFile(t, reportDir, "logs-0001.log.gz", true, "log") + checkUploadedFile(t, reportDir, "console.0.log.gz", true, "log") checkUploadedFile(t, reportDir, "logs-0002.log.gz", true, "test\n") // check file uploaded correctly @@ -156,7 +156,7 @@ log log log ------WebKitFormBoundarySsdgl8Nq9voFyhdO -Content-Disposition: form-data; name="log"; filename="instance-0.067644760733513781492004890379" +Content-Disposition: form-data; name="log"; filename="console.0.log" Content-Type: text/plain log @@ -207,7 +207,7 @@ func checkParsedMultipartUpload(t *testing.T, p *parsedPayload) { if p.Logs[0] != wanted { t.Errorf("Log 0: got %s, want %s", p.Logs[0], wanted) } - wanted = "logs-0001.log.gz" + wanted = "console.0.log.gz" if p.Logs[1] != wanted { t.Errorf("Log 1: got %s, want %s", p.Logs[1], wanted) }