Dmitrii Volosnykh
Dmitrii Volosnykh

Reputation: 1185

Use lift as a proxy

I want to forbid the full access to the Solr core from outside, and let it be used only for querying. Thus I am launching secondary server w/ connector instance inside Jetty servlet container (besides, the main webapp) on the port, that is not accessible from the WWW.

When there is incoming HTTP request to the liftweb application, I hook with RestHelper:

object Dispatcher extends RestHelper {
  serve {
    case List("api", a @ _*) JsonGet _ => JString("API is not implemented yet. rest: " + a)
  }
}

Targeting my browser to http://localhost/api/solr/select?q=region I get a response "API is not implemented yet. rest: List(solr, select)", so it seems to work. Now I want to do a connection on internal port (where Solr resides) in order to pass the query using the post-api part of the URL (i.e. http://localhost:8080/solr/select?q=region). I am catching the trailing REST-part of the URL (by means of a @ _*), but how can I access URL parameters? It would be ideal to pass a raw string (after api path element) to the Solr instance, just to prevent redundant parse/build steps. So applies to the Solr's response: I would like to avoid parsing building JsonResponse.

This seems to be a good example on doing some HTTP-redirection, but then I would have to open the hidden Solr's port, as far as I can understand.

What is the most effective way to cope with this task?

EDIT:

Well, I missed that after JsonGet comes Req value, which has all the needed info. But is there still a way to avoid unwanted parsing/composing URL to hidden port and JSON-response?

SOLUTION:

This is what I've got consdering Dave's suggestion:

import net.liftweb.common.Full
import net.liftweb.http.{JsonResponse, InMemoryResponse}
import net.liftweb.http.provider.HTTPRequest
import net.liftweb.http.rest.RestHelper
import dispatch.{Http, url}

object ApiDispatcher extends RestHelper {
  private val SOLR_PORT = 8080

  serve { "api" :: Nil prefix {
    case JsonGet(path @ List("solr", "select"), r) =>
      val u = localApiUrl(SOLR_PORT, path, r.request)
      Http(url(u) >> { is =>
        val bytes = Stream.continually(is.read).takeWhile(-1 !=).map(_.toByte).toArray
        val headers = ("Content-Length", bytes.length.toString) ::
          ("Content-Type", "application/json; charset=utf-8") :: JsonResponse.headers
        Full(InMemoryResponse(bytes, headers, JsonResponse.cookies, 200))
      })
  }}

  private def localApiUrl(port: Int, path: List[String], r: HTTPRequest) =
    "%s://localhost:%d/%s%s".format(r.scheme, port, path mkString "/", r.queryString.map("?" + _).openOr(""))
}

Upvotes: 0

Views: 387

Answers (1)

Dave Whittaker
Dave Whittaker

Reputation: 3102

I'm not sure that I understand your question, but if you want to return the JSON you receive from solr without parsing it you could use a net.liftweb.http.InMemoryResponse that contains a byte[] representation of the JSON.

Upvotes: 1

Related Questions