my problem is that i am getting a 400 bad request when i try to get a responce to my HTTP request.
Can anyone tell me why this is happening and possibly how i can fix it?
The exact error is :
BadRequestNo change in settings specified
I put in a breakpoint in my code before i pass in the configuration file, when i viewed it, it had changed what i wanted it to change and so the configuration file that already exists is definetly diffirent to the one i am trying to change it with.
Here is the api info for the configuration change : http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx
And Below is my code,Any help is greatly appreciated, thank you
public void changeConfiguration(string serviceName, string deploymentSlot, string config, string deploymentName)
{
//encoding the config file
byte[] encodedConfigbyte = new byte[config.Length];
encodedConfigbyte = System.Text.Encoding.UTF8.GetBytes(config);
string temp = Convert.ToBase64String(encodedConfigbyte);
//creating the URI with the subscriptionID,serviceName and deploymentSlot
Uri changeConfigRequestUri = new Uri("https://management.core.windows.net/" + subscriptionId + "/services/hostedservices/" + serviceName + "/deploymentslots/" + deploymentSlot + "/?comp=config");
//creating a request using the URI
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(changeConfigRequestUri);
//Adding a header to the request
request.Headers.Add("x-ms-version", "2010-10-28");
request.Method = "POST";
//Create a string to hold the request body, temp being the config file
string bodyText = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<ChangeConfiguration xmlns=\"http://schemas.microsoft.com/windowsazure\"" + ">"
+ "<Configuration>" + temp + "</Configuration></ChangeConfiguration>";
//encoding the body
byte[] buf = Encoding.ASCII.GetBytes(bodyText);
request.ContentType = "application/xml";
request.ContentLength = buf.Length;
//searches the cert store for a cert that has a matching thumbprint to the thumbprint supplied
X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
certStore.Open(OpenFlags.ReadOnly);
}
catch (Exception e)
{
if (e is CryptographicException)
{
Console.WriteLine("Error: The store is unreadable.");
}
else if (e is SecurityException)
{
Console.WriteLine("Error: You don't have the required permission.");
}
else if (e is ArgumentException)
{
Console.WriteLine("Error: Invalid values in the store.");
}
else
{
throw;
}
}
X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
certStore.Close();
if (certCollection.Count == 0)
{
throw new Exception("Error: No certificate found containing thumbprint ");
}
X509Certificate2 certificate = certCollection[0];
//cert is added to the request
request.ClientCertificates.Add(certificate);
//the requestBody is written to the request
Stream dataStream = request.GetRequestStream();
dataStream.Write(buf, 0, buf.Length);
dataStream.Close();
try
{
//retrieving responce
WebResponse response = (HttpWebResponse)request.GetResponse();
}
catch (WebException e)
{
string test = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
}
}
}
BadRequest means a parameter was incorrect. My guess is that you are using a deploymentSlot of 0 instead of staging or production like it is mentioned here:
http://msdn.microsoft.com/en-us/library/ee460786.aspx
Other then that, it would be great if you could show us the parameters you are passing in and we can maybe tell from that what is wrong.
Related
I'm getting a 500 internal server error when trying to access cherwell REST api via Code trying to return a token to make other calls. I've verified that all the information (username, password, ClientID, and client secret) are all correct. I've also verified the server is up and accepting requests. Something must be wrong with my code. Any help would be great!
string token = "";
string responseBody;
string serverName = "ql1cwbeta1";
//initialize web client
using (WebClient webClient = new WebClient())
{
// pull down parameters for body
string grantType = ConfigurationManager.AppSettings["grant_type"];
string clientId = ConfigurationManager.AppSettings["client_id"];
string username = ConfigurationManager.AppSettings["username"];
string password = ConfigurationManager.AppSettings["password"];
string authMode = ConfigurationManager.AppSettings["auth_mode"];
//add parameters in headers
webClient.Headers.Add("Accept", "application/json");
// adding parameters in body
NameValueCollection values = new NameValueCollection
{
{"grant_type", grantType},
{"client_id", clientId},
{"username", username},
{"password", password},
{"auth_mode", authMode}
};
try
{
byte[] responseBytes = webClient.
UploadValues("http://" + serverName + "/CherwellAPI/token?auth_mode=" + authMode + "&api_key=" + clientId, "POST", values);
responseBody = Encoding.UTF8.GetString(responseBytes);
}
catch (Exception exception)
{
return exception;
}
Hope below code may help you.
public static string TokenRequest()
{
try
{
// Create HTTP Web Request for the token request
HttpWebRequest tokenRequest = (HttpWebRequest)WebRequest.Create(Values.TokenURL);
byte[] data = Encoding.ASCII.GetBytes("username=" + Username + "&password=" + Password + "&client_id=" + ClientId + "&grant_type=" + GrantType);
// Set request verb POST, content type and content length (length of data)
tokenRequest.Method = "POST";
tokenRequest.ContentType = "application/x-www-form-urlencoded";
tokenRequest.ContentLength = data.Length;
// Stream request data
using (Stream stream = tokenRequest.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
// Get the response and read stream to string
using (WebResponse response = tokenRequest.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
using (StreamReader sr = new StreamReader(stream))
{
// responseText = sr.ReadToEnd();
return sr.ReadToEnd();
}
}
}
}
catch (WebException ex)
{
// Catch error for bad URL (404) or bad request (400) resulting from bad input (username, password, client id, grant type in token request)
if (ex.Message.Contains("400"))
{
// do something for bad request
}
else if (ex.Message.Contains("404"))
{
// do something for not found
}
else
{
// unknown error, do something
}
return null;
}
catch (Exception ex)
{
// General Exception
return null;
}
}
For future reference - You can include the client ID as part of the querystring if all parameters are included in the querystring, but if you are also sending a payload, then authmode should be the only thing in the querystring.
It will accept all of these parameters as querystrings.
However, you should know that for Cherwell specifically, if you are using LDAP auth / user accounts, you may need to URL encode your username values.
There are certain special characters that will break the auth command. Specifically, including a backslash for a domain can cause issues if it's not escaped with %5C , which I believe can cause a 400 error.
Also a cause of an error can be if you've chosen an authmode that's not enabled for the browser apps in the Security Settings page of the admin console ;)
So using Wit.ai I'm trying to use speech to text. I am using the Wit3D example from Github: https://github.com/afauch/wit3d/blob/master/Assets/UserScripts/Wit3D.cs
Recording of sound and saving to the .wav file works just fine. Sending the request to the server does not.
The .wav file is valid as I get a response when manually making a request through Postman.
The request code looks like this:
string GetJSONText(string file)
{
// get the file w/ FileStream
FileStream filestream = new FileStream(file, FileMode.Open, FileAccess.Read);
BinaryReader filereader = new BinaryReader(filestream);
byte[] BA_AudioFile = filereader.ReadBytes((Int32)filestream.Length);
filestream.Close();
filereader.Close();
//var bytes = File.ReadAllBytes(Path.Combine(Application.dataPath, "sample.wav"));
// create an HttpWebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.wit.ai/speech?v=20160901");
request.Method = "POST";
request.Headers["Authorization"] = "Bearer 3XFWDOBVS65V5A2VZWZFBB2PHOKDWGOH";
request.ContentType = "audio/wav";
//request.Timeout = 10000;
request.GetRequestStream().Write(BA_AudioFile, 0, BA_AudioFile.Length);
// Process the wit.ai response
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
print("Http went through ok");
StreamReader response_stream = new StreamReader(response.GetResponseStream());
return response_stream.ReadToEnd();
}
else
{
return "Error: " + response.StatusCode.ToString();
return "HTTP ERROR";
}
}
catch (Exception ex)
{
return "Error: " + ex.Message;
return "HTTP ERROR";
}
}
With or without putting a Timeout on the request I get the following Error message: "Error: The request timed-out"
Removing the line:
request.GetRequestStream().Write(BA_AudioFile, 0, BA_AudioFile.Length)
Will get me a response:
Error: Error getting response stream (Write: The authentication or decryption has failed.)
Which makes sense, because there is nothing to decrypt.
My firewall doesn't seem to be the problem. Any ideas of why there is a time-out? Using different methods of getting a byte[] didn't fix it either.
EDIT:
Putting the code in a normal Console application does work. So this seems to be a Unity issue.
Add this to top of your script:
using System.Collections.Generic;
Use this code.
public void SendRequest(string wavPath)
{
if(!File.Exists(wavPath))
{
Debug.Log("Invalid wav path.");
return;
}
StartCoroutine(SendRequestToWitAi(wavPath));
}
public IEnumerator SendRequestToWitAi(string wavPath)
{
string API_KEY = "3XFWDOBVS65V5A2VZWZFBB2PHOKDWGOH";
string url = "https://api.wit.ai/speech?v=20160526";
byte[] postData = File.ReadAllBytes(wavPath);
Dictionary<string, string> headers = new Dictionary<string, string>();
headers["Content-Type"] = "audio/wav";
headers["Authorization"] = "Bearer " + API_KEY;
float timeSent = Time.time;
WWW www = new WWW(url, postData, headers);
yield return www;
while (!www.isDone)
{
yield return null;
}
float duration = Time.time - timeSent;
if (www.error != null && www.error.Length > 0)
{
Debug.Log("Error: " + www.error + " (" + duration + " secs)");
yield break;
}
Debug.Log("Success (" + duration + " secs)");
Debug.Log("Result: " + www.text);
}
Use a JSON parser to parse www.text value. The "_text" field contains the result text.
I build a windows-mobile 6.5 application (based on cf 2.0) and have a problem with a special test case of one method. So I hope someone can give me an advice or has a helpful idea what the reason for this behaviour is...
The method is called continuous every 30 seconds from inside a thread, looks for files to be transferred via a HTTP request to a web server (jboss) and brings them on their way. The server url itself is under my control.
Everything works fine ... until I stop the web server and force an 503 server error. So far so good. But after restarting the web server, I would expect, that the next call of the transfer method will end in success - but it does not. Every further try ends in a timeout exception and I have to restart the application to make it work again.
So my question is: where is the problem, when I want to connect to an uri after an earlier try has failed with error 503? It seems, that there is something cached, but what the hell should it be?
Many thanks for every hint you have.
Juergen
public static Boolean HttpUploadFile2(string url, string file)
{
HttpWebRequest requestToServer = null;
WebResponse response = null;
try
{
Logger.writeToLogFileCom(string.Format("Uploading {0} to {1}", file, url));
requestToServer = (HttpWebRequest)WebRequest.Create(url);
requestToServer. Timeout = 40000;
string boundaryString = "----SSLBlaBla";
requestToServer.AllowWriteStreamBuffering = false;
requestToServer.Method = "POST";
requestToServer.ContentType = "multipart/form-data;
boundary=" + boundaryString;
requestToServer.KeepAlive = false;
ASCIIEncoding ascii = new ASCIIEncoding();
string boundaryStringLine = "\r\n--" + boundaryString + "\r\n";
byte[] boundaryStringLineBytes = ascii.GetBytes(boundaryStringLine);
string lastBoundaryStringLine = "\r\n--" + boundaryString + "--\r\n";
byte[] lastBoundaryStringLineBytes = ascii.GetBytes(lastBoundaryStringLine);
// Get the byte array of the myFileDescription content disposition
string myFileDescriptionContentDisposition = String.Format(
"Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}",
"myFileDescription",
"A sample file description");
byte[] myFileDescriptionContentDispositionBytes
= ascii.GetBytes(myFileDescriptionContentDisposition);
string fileUrl = file;
// Get the byte array of the string part of the myFile content
// disposition
string myFileContentDisposition = String.Format(
"Content-Disposition: form-data;name=\"{0}\"; "
+ "filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n",
"myFile", Path.GetFileName(fileUrl), Path.GetExtension(fileUrl));
byte[] myFileContentDispositionBytes =
ascii.GetBytes(myFileContentDisposition);
FileInfo fileInfo = new FileInfo(fileUrl);
// Calculate the total size of the HTTP request
long totalRequestBodySize = boundaryStringLineBytes.Length * 2
+ lastBoundaryStringLineBytes.Length
+ myFileDescriptionContentDispositionBytes.Length
+ myFileContentDispositionBytes.Length
+ fileInfo.Length;
// And indicate the value as the HTTP request content length
requestToServer.ContentLength = totalRequestBodySize;
// Write the http request body directly to the server
using (Stream s = requestToServer.GetRequestStream())
{
//TIMEOUT OCCURED WHEN CALLING GetRequestStream
// Send the file description content disposition over to the server
s.Write(boundaryStringLineBytes, 0, boundaryStringLineBytes.Length);
s.Write(myFileDescriptionContentDispositionBytes, 0,
myFileDescriptionContentDispositionBytes.Length);
// Send the file content disposition over to the server
s.Write(boundaryStringLineBytes, 0, boundaryStringLineBytes.Length);
s.Write(myFileContentDispositionBytes, 0,
myFileContentDispositionBytes.Length);
// Send the file binaries over to the server, in 1024 bytes chunk
FileStream fileStream = new FileStream(fileUrl, FileMode.Open,
FileAccess.Read);
byte[] buffer = new byte[1024];
int bytesRead = 0;
Logger.writeToLogFileCom("writing data...");
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
s.Write(buffer, 0, bytesRead);
} // end while
fileStream.Close();
Logger.writeToLogFileCom("... finished, File closed");
// Send the last part of the HTTP request body
s.Write(lastBoundaryStringLineBytes, 0, lastBoundaryStringLineBytes.Length);
Logger.writeToLogFileCom("... finished, File closed");
} // end using
// Grab the response from the server. WebException will be thrown
// when a HTTP OK status is not returned
Logger.writeToLogFileCom("lese Response");
response = requestToServer.GetResponse();
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string replyFromServer = responseReader.ReadToEnd();
response.Close();
if (Regex.Split(Regex.Split(replyFromServer, "content\\:RESPONSE\"\\>")[1], "\\</span\\>")[0].Equals("OK"))
{
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
Logger.writeToLogFileCom("Fehler im HTML Sender");
Logger.writeToLogFileCom(ex.Message);
Logger.writeToLogFileCom(ex.StackTrace);
}
finally
{
try
{
if (response != null)
{
response.Close();
}
}
catch (Exception ex) { }
}
return false;
}
I solved the problem.
I added an additional try / catch block inside the finally clause to call getResponse in every situation.
finally
{
try { response = requestToServer.GetResponse(); }
catch (Exception ex) { }
[...]
I'm trying to authenticate a user for the Azure management API. I'm following this tutorial for that:
http://msdn.microsoft.com/en-us/library/windowsazure/ee460782.aspx
However, when I execute it, I always get a "certificate not found" error. What could cause this? My code is exactly the same as in the example:
// Values for the subscription ID and List Hosted Services operation.
//
string subscriptionId = "****************";
// The opperation to be performed. This value can be modified to reflect the operation being performed.
string operationName = "hostedservices";
// Build a URI for https://management.core.windows.net/<subscription-id>/services/<operation-type>
Uri requestUri = new Uri("https://management.core.windows.net/"
+ subscriptionId
+ "/services/"
+ operationName);
// Create the request and specify attributes of the request.
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Define the requred headers to specify the API version and operation type.
request.Headers.Add("x-ms-version", "2010-10-28");
request.Method = "GET";
request.ContentType = "application/xml";
// The thumbprint value of the management certificate.
// You must replace the string with the thumbprint of a
// management certificate associated with your subscription.
string certThumbprint = "*************";
// Create a reference to the My certificate store.
X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
// Try to open the store.
try
{
certStore.Open(OpenFlags.ReadOnly);
}
catch (Exception e)
{
if (e is CryptographicException)
{
Console.WriteLine("Error: The store is unreadable.");
}
else if (e is SecurityException)
{
Console.WriteLine("Error: You don't have the required permission.");
}
else if (e is ArgumentException)
{
Console.WriteLine("Error: Invalid values in the store.");
}
else
{
throw;
}
}
// Find the certificate that matches the thumbprint.
X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, certThumbprint, false);
certStore.Close();
// Check to see if our certificate was added to the collection. If no, throw an error, if yes, create a certificate using it.
if (0 == certCollection.Count)
{
throw new Exception("Error: No certificate found containing thumbprint " + certThumbprint);
}
// Create an X509Certificate2 object using our matching certificate.
X509Certificate2 certificate = certCollection[0];
// Attach the certificate to the request.
request.ClientCertificates.Add(certificate);
try
{
// Make the call using the web request.
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// Display the web response status code.
Console.WriteLine("Response status code: " + response.StatusCode);
// Display the request ID returned by Windows Azure.
if (null != response.Headers)
{
Console.WriteLine("x-ms-request-id: "
+ response.Headers["x-ms-request-id"]);
Console.ReadKey();
}
// Parse the web response.
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
// Display the raw response.
Console.WriteLine("Response output:");
Console.WriteLine(reader.ReadToEnd());
Console.ReadKey();
// Close the resources no longer needed.
response.Close();
responseStream.Close();
reader.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
Here is the working code in Python (using cURL):
#!/usr/bin/python
import pycurl
c = pycurl.Curl()
values = [
("key", "YOUR_API_KEY"),
("image", (c.FORM_FILE, "file.png"))]
# OR: ("image", "http://example.com/example.jpg"))]
# OR: ("image", "BASE64_ENCODED_STRING"))]
c.setopt(c.URL, "http://imgur.com/api/upload.xml")
c.setopt(c.HTTPPOST, values)
c.perform()
c.close()
Here's what I have in C#:
public void UploadImage()
{
//I think this line is doing something wrong.
//byte[] x = File.ReadAllBytes(#"C:\Users\Sergio\documents\visual studio 2010\Projects\WpfApplication1\WpfApplication1\Test\hotness2.jpg");
//If I do it like this, using a direct URL everything works fine.
string parameters = #"key=1b9189df79bf3f8dff2125c22834210903&image=http://static.reddit.com/reddit.com.header.png"; //Convert.ToBase64String(x);
WebRequest webRequest = WebRequest.Create(new Uri("http://imgur.com/api/upload"));
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(parameters);
Stream os = null;
try
{ // send the Post
webRequest.ContentLength = bytes.Length; //Count bytes to send
os = webRequest.GetRequestStream();
os.Write(bytes, 0, bytes.Length); //Send it
}
catch (WebException ex)
{
MessageBox.Show(ex.Message, "HttpPost: Request error");
}
finally
{
if (os != null)
{
os.Close();
}
}
try
{ // get the response
WebResponse webResponse = webRequest.GetResponse();
StreamReader sr = new StreamReader(webResponse.GetResponseStream());
MessageBox.Show(sr.ReadToEnd().Trim());
}
catch (WebException ex)
{
MessageBox.Show(ex.Message, "HttpPost: Response error");
}
}
Now, the things I noticed is that when I changed my API key in the parameters string to "239231" or whatever number, the response I got was: "Invalid API key." So I think something must be working right.
I placed my correct API key and now I get a different response: "Invalid image format. Try uploading a JPEG image."
The service I'm using accepts almost every image format, so I am 100% certain the error is in the way I'm sending the file. Can anyone shed some light?
EDIT!!!
It turns out when I upload a JPG image I get that gray box thing. If I upload a big jpg image I don't get anything. For example: http://i.imgur.com/gFsUY.jpg
When I upload PNG's, the image uploaded doesn't even show.
I'm certain the issue is the encoding. What can I do?
EDIT 2!!!
Now I'm 100% certain that the problem lies in the first line of the method. The File.ReadAllBytes() must be doing something wrong. If I upload a URL file, every works peachy: http://imgur.com/sVH61.png
I wonder what encoding I should use. :S
Try this:
string file = #"C:\Users\Sergio\documents\visual studio 2010\Projects\WpfApplication1\WpfApplication1\Test\Avatar.png";
string parameters = #"key=1df918979bf3f8dff2125c22834210903&image=" +
Convert.ToBase64String(File.ReadAllBytes(file));
You should correctly form a multipart POST request. See an example here: Upload files with HTTPWebrequest (multipart/form-data)
Read image posted by in API
public IHttpActionResult UpdatePhysicianImage(HttpRequestMessage request)
{
try
{
var form = HttpContext.Current.Request.Form;
var model = JsonConvert.DeserializeObject<UserPic>(form["json"].ToString());
bool istoken = _appdevice.GettokenID(model.DeviceId);
if (!istoken)
{
statuscode = 0;
message = ErrorMessage.TockenNotvalid;
goto invalidtoken;
}
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
// var filePath = uploadPath + postedFile.FileName;
// string fileUrl = Utility.AbsolutePath("~/Data/User/" + model.UserId.ToString());
string fileUrl = Utility.AbsolutePath("~/" + Utility.UserDataFolder(model.UserId, "Document"));
if (!Directory.Exists(fileUrl))
{
Directory.CreateDirectory(fileUrl);
Directory.CreateDirectory(fileUrl + "\\" + "Document");
Directory.CreateDirectory(fileUrl + "\\" + "License");
Directory.CreateDirectory(fileUrl + "\\" + "Profile");
}
string imageUrl = postedFile.FileName;
string naviPath = Utility.ProfileImagePath(model.UserId, imageUrl);
var path = Utility.AbsolutePath("~/" + naviPath);
postedFile.SaveAs(path);
docfiles.Add(path);
if (model.RoleId == 2)
{
var doctorEntity = _doctorProfile.GetNameVideoChat(model.UserId);
doctorEntity.ProfileImagePath = naviPath;
_doctorProfile.UpdateDoctorUpdProfile(doctorEntity);
}
else
{
var patientEntity = _PatientProfile.GetPatientByUserProfileId(model.UserId);
patientEntity.TumbImagePath = naviPath;
_PatientProfile.UpdatePatient(patientEntity);
}
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
catch (Exception e)
{
statuscode = 0;
message = "Error" + e.Message;
}
invalidtoken:
return Json(modeldata.GetData(statuscode, message));
}
Try changing :-
"application/x-www-form-urlencoded"
to
"multipart/form-data"
Try adding the content-type for the jpg into your multipart boundary.
See this uRL for examples (at the end)
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2
Shot in the dark, but maybe create an instance of Image, save the file to a Stream and use that to read the bytes into an array then upload it.
As in:
Image i = System.Drawing.Image.FromFile("wut.jpg");
Stream stm = new Stream();
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
System.Drawing.Imaging.EncoderParameters paramz = new System.Drawing.Imaging.EncoderParameters(1);
myEncoderParameter = new EncoderParameter(myEncoder, 100L);
paramz.Param[0] = myEncoderParameter;
i.Save(stm, System.Drawing.Imaging.ImageFormat.Jpeg, paramz);
/* I'm lazy: code for reading Stream into byte[] here */