Skip to content

Instantly share code, notes, and snippets.

@Russtopia
Last active February 16, 2024 11:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Russtopia/dc913026b1da3754ff1fea107d1a7cdf to your computer and use it in GitHub Desktop.
Save Russtopia/dc913026b1da3754ff1fea107d1a7cdf to your computer and use it in GitHub Desktop.
Golang CGI file upload example using net/http/cgi
// Simple demo of a GO CGI program that takes
// file uploads.
//
// NOTE NOTE DANGER DANGER
// Absolutely No filename/path sanitizing is done,
// don't run this in production unless you want hackers
// to overwrite your server. This is only a demo of
// how to untangle the go stdlib form-related datatypes
// and use them to take file uploads.
//
package main
// upload form with drag and drop using CSS
// Ref: https://codepen.io/TheLukasWeb/pen/qlGDa/
// For a wonderful clarification of the various CGI form
// encodings:
// https://stackoverflow.com/questions/4526273/what-does-enctype-multipart-form-data-mean
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/cgi"
"os"
)
func main() {
// First we must get the CGI request info from
// the server-provided CGI env
r, err := cgi.Request()
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
} else {
fmt.Fprintf(os.Stderr, "[dbg] got CGI request\n")
}
//!// For simple forms... (default form type: application/x-www-form-urlencoded)
//!if err = r.ParseForm(); err != nil {
//! fmt.Fprintf(os.Stderr, err.Error())
//! os.Exit(1)
//!}
// For multi-part (eg., file upload) forms...
// (multipart/form-data)
if err = r.ParseMultipartForm(65536); err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
fmt.Printf("Content-type: text/html\n\n")
fmt.Printf("<!DOCTYPE html>\n")
fmt.Println("<html><head><title>Test</title></head><body>")
fmt.Println("<pre>")
fmt.Printf("1: Request: %+v\n", r)
fmt.Println("</pre>")
fmt.Println("<pre>")
fmt.Printf("2: form.Form (url.Values):%+v\n", r.Form)
fmt.Println("</pre>")
fmt.Println("<pre>")
fmt.Printf("3: multipart.Form.Value[]:%+v\n", r.MultipartForm.Value)
fmt.Println("</pre>")
fmt.Println("<pre>")
// MultipartForm.File[] is a map keyed by form field name (ie., there can be
// multiple file upload form fields... I guess.)
for k := range(r.MultipartForm.File) {
// Individual files are described in each .File[k]
fhdr := r.MultipartForm.File[k] // []*multipart.FileHeader
for idx := 0; idx < len(fhdr); idx++ {
fmt.Printf("4(%d):%s %d\n", idx, fhdr[idx].Filename, fhdr[idx].Size)
fData := make([]byte, fhdr[idx].Size)
file, _ := fhdr[idx].Open()
file.Read(fData)
ioutil.WriteFile(fhdr[idx].Filename, fData, 0755)
}
}
fmt.Println("</pre>")
fmt.Println("</body></html>")
}
<html>
<head>
<link rel="stylesheet" media="all" href="main.css" />
<!-- Ref: https://codepen.io/TheLukasWeb/pen/qlGDa/ -->
</head>
<body>
<form action="../cgi-bin/go-cgi-upload.cgi" method="POST" enctype="multipart/form-data">
<input type="hidden" id="hidden1" name="hiddenField1" value="none">
<input type="file" name="uploadFiles" multiple>
<p>Drag your files here or click in this area.</p>
<button type="submit">Upload</button>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
$(document).ready(function(){
$('form input').change(function () {
$('form p').text(this.files.length + " file(s) selected");
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment