Golang : How to transmit update file to client by HTTP request example




Alright, got a friend here that wants a simple Golang http server that will handle updates to his software. Basically, his Android/iOS/desktop app needs to be updated from time to time with the latest data file. At the same time, he is also concern about security and don't want to serve the update files to any clients that request it.

Below is a simple update server that will transmit the update file upon request by any client. The client will initiate HTTP request to the update server and it will perform some sanity checks before transmitting.

The only authentication is that the request must provide the correct parameter in order to initiate the server to start transmitting the file. If the client's request parameter is incorrect, this program will not proceed.

Here you go!


 package main

 import (
  "io"
  "log"
  "net"
  "net/http"
  "os"
  "strconv"
 )

 func main() {
  http.HandleFunc("/", downloadToClient)

  port := ":8080"
  log.Println("Download update files from localhost" + port)
  err := http.ListenAndServe(port, nil)
  if err != nil {
 log.Println(err)
  }

 }

 func downloadToClient(w http.ResponseWriter, r *http.Request) {

  // there is where we want to do some simple verification
  // if the app(client) did not supply the correct parameter, which is - "updatefile"
  // abort!

  fileName := r.URL.Query().Get("updatefile")

  if fileName == "" {
 // return 400 HTTP response code for BAD REQUEST
 http.Error(w, "Update failed due to malformed URL.", 400)
 return
  }

  // For more advance authentication, see
  // https://www.socketloop.com/tutorials/golang-simple-client-server-hmac-authentication-without-ssl-example

  // get client ip address
  ip, _, _ := net.SplitHostPort(r.RemoteAddr)

  log.Println("Transmiting to client at " + ip + " : " + fileName)

  // Do we have the update with the given filename?

  updateFile, err := os.Open(fileName)

  defer updateFile.Close()

  if err != nil {
 // return 404 HTTP response code for File not found
 http.Error(w, "Update file not found.", 404)
 return
  }

  // Prepare the update file to be sent over to the client(which in this case is an APP)

  fileHeader := make([]byte, 512) // 512 bytes is sufficient for http.DetectContentType() to work
  updateFile.Read(fileHeader) // read the first 512 bytes from the updateFile
  fileType := http.DetectContentType(fileHeader) // set the type

  fileInfo, _ := updateFile.Stat()
  fileSize := fileInfo.Size()

  //Transmit the headers
  w.Header().Set("Expires", "0")
  w.Header().Set("Content-Transfer-Encoding", "binary")
  w.Header().Set("Content-Control", "private, no-transform, no-store, must-revalidate")
  w.Header().Set("Content-Disposition", "attachment; filename="+fileName)
  w.Header().Set("Content-Type", fileType)
  w.Header().Set("Content-Length", strconv.FormatInt(fileSize, 10))

  //Send the file
  updateFile.Seek(0, 0)  // reset back to position since we've read first 512 bytes of data previously
  io.Copy(w, updateFile) // transmit the updatefile bytes to the client
  return
 }

Example of proper execution, the server has an update file call data.zip

Run the server and point your browser, curl or POST request to localhost:8080?updatefile=data.zip

NOTE: For production use, it is advisable to make sure that any requests made either by APP or browsers to be authenticated first with HMAC or some secret update codes. This is to ensure your app or service integrity.

References :

https://www.socketloop.com/tutorials/golang-force-download-file-example

https://www.socketloop.com/tutorials/golang-simple-client-server-hmac-authentication-without-ssl-example

  See also : Golang : Force download file example





By Adam Ng(黃武俊)

IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.


Advertisement