Skip to content

Instantly share code, notes, and snippets.

@ymnk
Created April 8, 2009 15:27
Show Gist options
  • Save ymnk/91826 to your computer and use it in GitHub Desktop.
Save ymnk/91826 to your computer and use it in GitHub Desktop.
import java.io.{ByteArrayOutputStream, IOException, OutputStream, File}
import java.io.{File, FileInputStream, DataInputStream}
import java.net.{URL, URLConnection, HttpURLConnection}
import java.util.Random
abstract sealed class Param
case class FieldParam(key:String, value:String) extends Param
case class DataParam(key:String, filename:String,
data:Array[Byte], typ:Option[String]) extends Param
case class FileParam(key:String, file:File, typ:Option[String]) extends Param
object PostMultiPartFormData {
private lazy val boundary:Array[Byte] = {
val chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
val rand = new Random()
(0 until 10).foldLeft(new StringBuilder){
case (b, _) => b.append(chars(rand.nextInt(chars.length)))
}.toString.getBytes
}
def apply(url:String, param:Param*):Option[String] = {
try{
val con = new URL(url).openConnection match{
case con:HttpURLConnection => con
case _ => throw new Exception
}
con.setUseCaches(false)
con.setDoOutput(true)
con.setRequestProperty("Content-Type",
"multipart/form-data; boundary=%s".format(new String(boundary)))
implicit val baos = new ByteArrayOutputStream
param foreach {
case FieldParam(k, v) => writeField(k, v)
case DataParam(k, f, d, t) => writeData(k, f, d, t)
case FileParam(k, f, t) =>
val data = new Array[Byte](f.length.asInstanceOf[Int])
new DataInputStream(new FileInputStream(f)) match{
case i => i.readFully(data); i.close
}
writeData(k, f.getName, data, t)
}
writeEnd
baos.flush
baos.close
con.setRequestProperty("Content-Length", baos.size.toString)
con.getOutputStream match{
case cout =>
baos.writeTo(cout)
cout.close
}
con.getResponseCode match{
case code if code!=200 => None
case _ =>
val result = new StringBuilder
con.getInputStream match{
case in =>
for(c <- Stream.const(in.read _).map(_()).takeWhile(_ != -1))
result.append(c.toChar)
in.close
}
Some(result.toString)
}
}
catch{
case ioe => return None
}
}
private val CRLF = "\r\n".getBytes
private val -- = "--".getBytes
private val cd = "Content-Disposition: form-data; name=\"%s\""
private def writeField(k:String, v:String)(implicit b:OutputStream){
write(--, boundary, CRLF)
write(cd.format(k).getBytes, CRLF)
write(CRLF)
write(v.getBytes, CRLF)
}
private val cdf = "Content-Disposition: form-data; name=\"%s\"; filename=\"%s\""
private val ct = "Content-Type: %s"
private val os = "application/octet-stream"
private def writeData(k:String, f:String, d:Array[Byte], t:Option[String])
(implicit b:OutputStream){
val typ = (t getOrElse os)
write(--, boundary, CRLF)
write(cdf.format(k, f).getBytes, CRLF)
write(ct.format(typ).getBytes, CRLF)
write(CRLF)
write(d, CRLF)
}
private def writeEnd(implicit b:OutputStream){
write(--, boundary, --, CRLF)
}
private def write(data:Array[Byte]*)(implicit b:OutputStream){
data.foreach(b.write(_))
}
}
/*
object Test {
def main(arg:Array[String]){
import java.io._
val f = new File(arg(0))
val data = new Array[Byte](f.length.asInstanceOf[Int])
new DataInputStream(new FileInputStream(f)) match{
case fis => fis.readFully(data); fis.close
}
val result =
PostMultiPartFormData("http://127.0.0.1/post",
FieldParam("MAX_FILE_SIZE", "1000"),
// FileParam("upload", f, None),
DataParam("upload", arg(0), data, None))
println(result getOrElse "error")
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment