1

I am trying to create a webservice which will send and receive large files, as part of a storage solution for remote backups.

When a request is received by the webserver it needs to be authenticated before it stores the data.

At the moment I'm considering sending sending authentication methods in the headers and the actual content in the body. Fairly standard.

However I would like to know, due to the size of the body, if it is possible to authenticate the headers, and possibly respond to the request/drop the connection before completely receiving the body, if the request cannot be validated?

I haven't started implementing yet, but I am leaning towards an implementation using Golang. There will be an nginx server in front of it, in case it makes any difference.

Edit:

Maybe I haven't been clear enough, in my original question, but the main focus should be: Is it possible to figure out if a request is authenticated before receiving the entire payload and possibly drop the connection/respond if that is not the case?

Like.. Is it possible to interpret the request as a stream, where you can act on just the first part, even though the rest of the payload hasn't arrived yet.

Sorry for the confusion.

RckMrkr
  • 985
  • 1
  • 10
  • 14

3 Answers3

0

I would like to know, due to the size of the body, if it is possible to authenticate the headers, and possibly respond to the request/drop the connection before completely receiving the body, if the request cannot be validated?

This is how authentication work: you validate the user before getting the requested url.

You do it through any auth middleware like:

More on the authentication alternatives in "End-user authentication for Go web applications".

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
0

Most of the time you would use a session with the great package sessions from Gorilla. But you could make it without with the "het/http" package. in this exemple there is tow files main.go and index.html into the public folder

Server side in go (main.go)

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "log"
    "net/http"
)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/get/token", getTokenHandler)
    r.HandleFunc("/send/token", sendTokenHandler)
    r.PathPrefix("/").Handler(http.FileServer(http.Dir("./public/")))
    http.Handle("/", r)
    log.Println("Listening...")
    http.ListenAndServe(":3000", nil)
}

func getTokenHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Add("secret-token", "abcd")
    fmt.Fprint(w, "abcd")
}

func sendTokenHandler(w http.ResponseWriter, r *http.Request) {
    mySecret := r.Header.Get("secret-token")
    if mySecret != "abcd" {
        w.Header().Add("response-to-token", "false")
        fmt.Fprint(w, "you are not allowed")
    } else {
        w.Header().Add("response-to-token", "true")
        fmt.Fprint(w, "you are allowed")
    }
}

On the client side in javascript you may use a function to get the header infos like

Client side with JS (public/index.html)

<html>
    <head>
        <meta charset="utf-8">
        <title>Upload</title>
        <script type="text/javascript">

            var getSecret = function (){
                var req = new XMLHttpRequest();
                req.open('GET', "get/token", false);
                req.send();
                var secretToken = req.getResponseHeader("secret-token");
                document.getElementById('secretInput').value = secretToken;
            }

            var postSecret = function(){
                var secret = document.getElementById('secretInput').value;
                var req = new XMLHttpRequest();
                req.open('POST', "send/token", false);
                req.setRequestHeader("secret-token", secret);
                req.send();
                var responseToken = req.getResponseHeader("response-to-token");
                console.log(responseToken);
            }
            </script>
        </head>
        <body>
            <button onclick="getSecret()" >get Secret</button>
            <hr>
            <input id="secretInput" type="text"></input>
            <button onclick="postSecret()">post Secret</button>
        </body>
</html>

finally split your file

If your file is verry big you may want ton split it in parts so you could send a message if the token is not right. For the splitting part you can use Javascript. I've just found a solution in js on stackoverflow

Community
  • 1
  • 1
0

If you post the file as the body of your request you can use an auth header to validate without waiting for the file to fully upload.

You can then use io.Copy to copy from the request body to a file.

_, err := io.Copy(someFile, req.Body)

Don't use 'multipart/form-data' the http pkg will get in your way if you do. Posting the file as the body will let you access the contents of the request body as a stream and io.Copy will manage the copy to the file in a sensible way.

jmaloney
  • 11,580
  • 2
  • 36
  • 29