Last active
June 9, 2019 23:52
-
-
Save antonfisher/90c8ce5c3223f09a36a65e003fa6d2f4 to your computer and use it in GitHub Desktop.
HTTP PUT servers on Node.js and Go with calculating MD5 sums of uploaded files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Usage: | |
// env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server server.go && ./server | |
// Test: | |
// dd if=/dev/urandom of=./archive.2gb.zip bs=1024KB count=2000 | |
// time curl --upload-file archive.2gb.zip http://localhost:9001 | |
// | |
package main | |
import ( | |
"crypto/md5" | |
"fmt" | |
"io" | |
"net/http" | |
"os" | |
"path/filepath" | |
) | |
const port = 9001 | |
const destination = "/tmp" | |
func sendError(w http.ResponseWriter, message string, code int) { | |
w.WriteHeader(code) | |
fmt.Fprint(w, message) | |
} | |
func main() { | |
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { | |
fmt.Printf("%s %s\n", r.Method, r.URL.Path) | |
if r.Method != http.MethodPut { | |
w.WriteHeader(http.StatusMethodNotAllowed) | |
return | |
} | |
file := filepath.Join(destination, r.URL.Path) | |
// file writer | |
fw, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE, 0660) | |
defer fw.Close() | |
if err != nil { | |
sendError(w, err.Error(), http.StatusInternalServerError) | |
return | |
} | |
// md5 writer | |
hw := md5.New() | |
// multiwriter to write to both file and md5 hash writers | |
mw := io.MultiWriter(fw, hw) | |
// write body to multiwriter | |
_, err = io.Copy(mw, r.Body) | |
if err != nil { | |
sendError(w, err.Error(), http.StatusInternalServerError) | |
return | |
} | |
w.WriteHeader(http.StatusOK) | |
fmt.Fprintf(w, "OK: %x\n", hw.Sum(nil)) | |
}) | |
fmt.Printf("Listening on port %d...\n", port) | |
http.ListenAndServe(fmt.Sprintf(":%d", port), nil) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Usage: | |
// node ./server.js | |
// Test: | |
// dd if=/dev/urandom of=./archive.2gb.zip bs=1024KB count=2000 | |
// time curl --upload-file archive.2gb.zip http://localhost:9001 | |
// | |
'use strict'; | |
const fs = require('fs'); | |
const path = require('path'); | |
const http = require('http'); | |
const crypto = require('crypto'); | |
const port = 9001; | |
const destination = '/tmp'; | |
function sendError(res, message = 'Internal error', status = 500) { | |
console.log(`ERROR: ${message} [${code}]`); | |
res.statusCode = status; | |
res.end(message); | |
} | |
http.createServer() | |
.on('request', (req, res) => { | |
console.log(req.method, req.url); | |
if (req.method !== 'PUT') { | |
return sendError(res, 'Method not allowed', 405); | |
} | |
const file = path.join(destination, req.url); | |
const writable = fs.createWriteStream(file); | |
const md5 = crypto.createHash('md5'); | |
req.on('data', chunk => md5.update(chunk)) | |
.once('error', err => sendError(res, err)) | |
.pipe(writable) | |
.once('error', err => sendError(res, err)) | |
.on('finish', () => res.end(`OK: ${md5.digest('hex')}\n`)); | |
}) | |
.listen(port, () => console.log(`Listening on ${port}...`)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment