HTTP authentication in Groovy?

daniel.lozynski picture daniel.lozynski · Mar 3, 2016 · Viewed 13.2k times · Source
def http = new HTTPBuilder(url)
http.auth.basic username, password

def data = new URL(url)

def response = data.getText()

def relativePaths = new XmlParser().parseText(response)

relativePaths.each {page ->

    def link = [email protected]()

    if(link.contains(".txt")){
        println link
    }

}

Hi,

when trying to run this, I get a 401. It seems like here:

def response = data.getText()

it is actually not authenticated anymore (or at all) ? In Ruby I would write it like that:

(open(url, :http_basic_authentication => [username, password])
data = Nokogiri::XML(open(url, :http_basic_authentication => [username, password])))

How would that look like in Groovy ? Am I using httpbuilder wrong ? Thanks a lot in advance !

Update 1:

After applying the changes:

def http = new HTTPBuilder(url)
http.auth.basic username, password

http.get(path: url, contentType: ContentType.TEXT) { resp, reader ->

    def relativePaths = new XmlParser().parse(reader)

    relativePaths.each { page ->

        def link = [email protected]()

        if (link.contains(".txt")) {
            println link
        }
    }
}

I get an 406:

Response code: 406; found handler: org.codehaus.groovy.runtime.MethodClosure@5be46f9d Caught: groovyx.net.http.HttpResponseException: Not Acceptable groovyx.net.http.HttpResponseException: Not Acceptable

Update 2:

Still not working. I changed the contentType to XML and the path to the actual path, but getting an error message:

GET <URL>/<PATH>:(id:ContinuousIntegration_BuildTestDistribute)/artifacts/children/
Response code: 200; found handler: ArtifactDownloader$_run_closure1@5be46f9d
Parsing response as: application/xml
Could not find charset in response; using UTF-8
Parsed data to instance of: class groovy.util.slurpersupport.NodeChild
Caught: groovy.lang.MissingMethodException: No signature of method: groovy.util.XmlParser.parse() is applicable for argument types: (groovy.util.slurpersupport.NodeChild) values: []
Possible solutions: parse(java.io.File), parse(java.io.InputStream), parse(java.io.Reader), parse(java.lang.String), parse(org.xml.sax.InputSource), use([Ljava.lang.Object;)
groovy.lang.MissingMethodException: No signature of method: groovy.util.XmlParser.parse() is applicable for argument types: (groovy.util.slurpersupport.NodeChild) values: []
Possible solutions: parse(java.io.File), parse(java.io.InputStream), parse(java.io.Reader), parse(java.lang.String), parse(org.xml.sax.InputSource), use([Ljava.lang.Object;)
    at ArtifactDownloader$_run_closure1.doCall(ArtifactDownloader.groovy:14)
    at groovyx.net.http.HTTPBuilder$1.handleResponse(HTTPBuilder.java:503)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:218)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:160)
    at groovyx.net.http.HTTPBuilder.doRequest(HTTPBuilder.java:515)
    at groovyx.net.http.HTTPBuilder.get(HTTPBuilder.java:285)
    at groovyx.net.http.HTTPBuilder$get.call(Unknown Source)
    at ArtifactDownloader.run(ArtifactDownloader.groovy:12)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Just for comparison, the Ruby script. Maybe httpbuilder is just not what I want ? I actually wanted to use it for authentication only.

(open(url, :http_basic_authentication => [username, password])
data = Nokogiri::XML(open(url, :http_basic_authentication => [username, password])))

relativePaths = data.xpath("//content/@href")

relativePaths.each { |path| 
    if path.text.include? ".apk"
        puts "<URL>:<PORT>"+path.text
    end
}

Answer

Emmanuel Rosa picture Emmanuel Rosa · Mar 3, 2016

Are you ready for a face palm?

You created an HTTPBuilder and... never used it. You got it all set up...

def http = new HTTPBuilder(url)
http.auth.basic(username, password)

... but then used a new URL to retrieve the data:

def data = new URL(url)
def response = data.getText()

Solution

An HTTPBuilder is used like this:

import groovyx.net.http.HTTPBuilder
import groovyx.net.http.ContentType

http.get(path : path, contentType : ContentType.TEXT) { resp, reader ->
    def relativePaths = new XmlParser().parse(reader)    
    ...
}

Note: I'm not sure whether the get() method runs in the background or not.

Updated solution

Setting the content type to XML instructs HTTPBuilder to parse the response and provide the parsed document as the second argument. The document is represented as a Node.

http.get(path : path, contentType : ContentType.XML) { response, node ->
    def relativePaths = node    
    ...
}