Stream directory content on the fly over HTTP using TAR archive

812 views
Skip to first unread message

Remi Ferrand

unread,
Aug 23, 2018, 12:39:01 PM8/23/18
to golang-nuts
Hi everyone,

This is my first message on this list so please apologize if this discussion has already showed up in the past.

What I'm trying to do is quite simple.

I do have a directory with files I want to share to a friend from my workstation.
I would like him to:
1. point his web browser to an URL
2. be prompted for credentials (basic auth' is ok for my use-case)
3. get a prompt to download a TAR archive that contains my workstation's directory and files structure.

My question is about the third point.

I do not want the TAR archive to be built on my workstation and then be sent over HTTP once the archive contains all the files.
Sometimes, my workstation does not have enough free disk space to store the temporary TAR archive and then send it.
I would like the TAR archive to be generated on the fly and streamed over HTTP without any storage on my workstation disk.

I've written a simple code here that does what I want.
Everything seems to work.

The code is written in hurry and I've used

exec.Command

to spawn the subprocess "tar cf -".
I would like to avoid using the external tar util.

I'm just starting in GoLang but I know that there is a package archive/tar that allows to create TAR archives.

I can't figure out how archive/tar can be used in my use case (i.e not generating the full TAR archive on my workstation and only then send it once the archive is generated).

If someone has already played with the archive/tar package and sees how I can use it to achieve what I want, any help would be appreciated in order to improve my GoLang skills

Thanks !

Cheers

Rémi



Tamás Gulácsi

unread,
Aug 23, 2018, 1:00:05 PM8/23/18
to golang-nuts
Just use "tw := tar.NewWriter(w)" where w is your http.ResponseWriter (it satisfies the io.Writer interface) after you checked everything and have set w.Header.Set("Content-Type", "application/x-tar").
Then for each file (use filepath.Walk) tw.WriteHeader(th) (of tar.FileInfoHeader(fi) of fi := fh.Stat())) then io.Copy(tw, fh):

tw := tar.NewWriter(w)
filepath
.Walk(".", func(path string, info os.FileInfo, err error) error {
 
if err != nil {
   
return err
 
}
  th
, err := tar.FileInfoHeader(info)
 
if err != nil {
   
return err
 
}
  fh
, err := os.Open(path)
 
if err != nil {
   
return err
 
}
  defer fh
.Close()
 
if err = tw.WriteHeader(th); err != nil {
   
return err
 
}
  _
, err = io.Copy(tw, fh)
 
return err
})



Remi Ferrand

unread,
Aug 24, 2018, 8:08:29 AM8/24/18
to golang-nuts
That's exactly what I wanted ! I was missing the `io.Writer` interface.

Thanks !

Cheers

Rémi
Reply all
Reply to author
Forward
0 new messages