jacquayj / GoRODS

Golang binding for iRODS C API: An iRODS client library written in Golang + C
https://godoc.org/github.com/jjacquay712/GoRODS
BSD 3-Clause "New" or "Revised" License
17 stars 5 forks source link

GoRODS for dummies, question #26

Closed matthdsm closed 7 years ago

matthdsm commented 7 years ago

Hi John,

I saw the presentation of GoRODS on irods.org, and was fairly impressed. We'd very much like to use this library.

We're looking to create a sort of proxy server that can serve data from a remote iRODS server over HTTP. More specifically, we're looking for something that understands standard GET byte range requests. Do you think this is possible using GoRODS?

To be completely honest, I've got no experience with golang whatsoever, so I'm kind of swimming in the deep here, but I'd really like to use this library. Your HOWTO is pretty clear byte ranges are supported, but if you could help me out with this specific case, that'd be really awesome.

Thanks for the info! M

PS, this is related to irods/irods#3471

jjacquay712 commented 7 years ago

Hey @matthdsm,

Thanks for checking out my presentation, so glad you enjoyed it!

For HTTP GET byte range support, check out the HTTP mount code as a working reference/example bundled in this repository: https://github.com/jjacquay712/GoRODS/blob/master/httphandler.go#L990

If you instantiate the HTTP mount like this:

package main

import (
    "fmt"
    "github.com/jjacquay712/GoRODS"
    "log"
    "net/http"
)

func main() {

    client, conErr := gorods.New(gorods.ConnectionOptions{
        Type: gorods.UserDefined,

        Host: "localhost",
        Port: 1247,
        Zone: "tempZone",

        Username: "rods",
        Password: "password",
    })

    // Ensure the client initialized successfully and connected to the iCAT server
    if conErr != nil {
        log.Fatal(conErr)
    }

    mountPath := "/irods/"

    // Setup the GoRODS FileServer
    fs := gorods.FileServer(gorods.FSOptions{
        Path:   "/tempZone/home/rods",
        Client: client,
        Download: true,
        StripPrefix: mountPath,
    })

    // Create the URL router
    mux := http.NewServeMux()

    // Serve the iRODS collection at /irods/
    mux.Handle(mountPath, http.StripPrefix(mountPath, fs))

    // Start HTTP server on port 8080
    log.Fatal(http.ListenAndServe(":8080", mux))

}

You'll get the HTTP byte range functionality for data objects, plus some HTML/CSS output if you GET a collection. You can always rip out the byte range code if you're looking to implement your own pure RESTful API or WebDAV type application. The bundled gorods.FileServer doesn't really conform to any standard (REST, WebDAV, etc...), except for what a web browser can understand. So improvements are definitely possible. I mainly added it into the repository as an example and a way for people to get started quickly.

There are also examples on how to serve & add metadata over HTTP, among others if you're interested in that functionality and more.

Hope this helps! Let me know if you have other questions or comments.

matthdsm commented 7 years ago

Hi,

Thanks for the pointers! The code above does work out of the box. I saw in the docs that the connection options support ticket based access. Is it possible to authenticate by adding the ticket as a get param? Or is this something we should figure out by ourselves as we build the application?

Thanks a lot! M

jjacquay712 commented 7 years ago

Yes, it is possible to utilize ticket-based authentication with the above example, with a few minor modifications:

client, conErr := gorods.New(gorods.ConnectionOptions{
        Type: gorods.UserDefined,

        Host: "localhost",
        Port: 1247,
        Zone: "tempZone",

        Username: "anonymous",
        Ticket: "iOpiAUaabxpQIqu", // Use ticket instead of a password here
})

You'll also need to wrap this client struct instantiation with an http.HandlerFunc so you can gain access to GET URL parameters. Here's some information on that technique.

There are a few caveats to using tickets at the moment:

matthdsm commented 7 years ago

Allright, everything is coming together it seems. Let's get coding!

Thanks again! M

jjacquay712 commented 7 years ago

Ok, I've verified that tickets are working and fixed a minor issue relating (see latest release). Let me know if you have any issues or questions.

-John

matthdsm commented 7 years ago

Hi John,

Thanks for the fix. I'm still running into an error because the CORS headers aren't set by default with net/http. Could you provide any help regarding this? Or is this a bit to much out of scope for you?

Thanks anyway. M

jjacquay712 commented 7 years ago

Hey @matthdsm,

CORS support seems to fall outside the scope of GoRODS, but here is some code from a past Ruby project (using the Sinatra framework) that you might find helpful. It should be simple enough to port to Golang:

# Runs before each request
before do

    # Add CORS support
    headers({
        'Access-Control-Allow-Origin' => '*'
    })

    headers({
        'Access-Control-Allow-Credentials' => 'true',
        'Access-Control-Allow-Methods' => 'GET,PUT,POST,DELETE,OPTIONS',
        'Access-Control-Allow-Headers' => 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version',
        'Access-Control-Max-Age' => '1728000'
    }) if request.request_method == 'OPTIONS'

end

This is also a good resource: https://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server