I wrote an IIS module and it's working fine.
I want to get the posted file from request.
In below code, I could get sent form data and view the file in header:
IHttpRequest * pHttpRequest = pHttpContext->GetRequest();
if (pHttpRequest != NULL)
{
LPCSTR body;
DWORD cbBytesReceived = 1024;
void * pvRequestBody = pHttpContext->AllocateRequestMemory(cbBytesReceived);
if (NULL == pvRequestBody)
{
pProvider->SetErrorStatus(hr);
return RQ_NOTIFICATION_FINISH_REQUEST;
}
if (pHttpRequest->GetRemainingEntityBytes() > 0)
{
while (pHttpRequest->GetRemainingEntityBytes() != 0)
{
hr = pHttpRequest->ReadEntityBody(
pvRequestBody, cbBytesReceived, false, &cbBytesReceived, NULL);
if (FAILED(hr))
{
if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
{
pProvider->SetErrorStatus(hr);
return RQ_NOTIFICATION_FINISH_REQUEST;
}
}
body = (LPCSTR)pvRequestBody;
pszResult = pszResult + body;
}
}
}
The result is:
-----------------------5r707ac9a9687yu
Content-Disposition: form-data; name="file"; filename="1.zip"
Content-Type: application/octet-stream
PKþóÐMš`_ÿív(X[úM/xvœ5a¢~¯²²ÊÆÎÈá"}å
lIœì*7·®-W§Xþn¹DçvÃŒØÀ>ÊHñ\N-kÂ¥ûºÂm'ŒäõÚÌŸÏŽ)ããSqŽT3ÕïDñ?ËWÇKy«zAÉ÷øŒ¿ÂÇ
I tried to cast file part(PKþóÐMš`_ÿív ...) to binary and write file, but file is curropted because the header contains all info (all posted files,content denposition,...) and not the clear binary file.
How can I write the sent files on disk(binary/text)?
Related
void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data)
{
if (ev == MG_EV_HTTP_MSG)
{
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_http_match_uri(hm, "/api/hello")) // On /api/hello requests,
{
char html[1000];
strcpy(html, "<!DOCTYPE html>"
"<html>"
"<head>"
"</head>"
"<body>"
"<form action=\"sum\" method = \"GET\">"
"<label> Number 1</label>"
"<input type=\"text\" name=\"number1\"> <br>"
"<label> Number 2</label>"
"<input type=\"text\" name=\"number2\"><br>"
"<input type=\"submit\" value=\"Add\">"
"</form>"
"</body>"
"</html>");
mg_http_reply(c, 200, "Content-Type: text/html\r\n", html);
}
else if(mg_http_match_uri(hm, "/api/sum"))
{
struct mg_str params = hm->body;
double num1, num2;
if(mg_json_get_num(params, "$[0]", &num1) &&
mg_json_get_num(params,"$[1]", &num2))
{
mg_http_reply(c, 200, "Content-Type: text/plain\r\n", "result:%g\n", num1 + num2);
}
else
{
mg_http_reply(c, 500, "NULL", "%s","Parameters Missing");
}
}
else // For all other URIs,
{
mg_http_reply(c, 200, "Content-Type: text/plain\r\n", "%s\n", "Static Content");
}
}
}
void task1(void)
{
struct mg_mgr mgr;
mg_mgr_init(&mgr); // Init manager
mg_http_listen(&mgr, "http://10.0.0.6:8000", fn, &mgr); // Setup listener
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
}
In the code main.c calls task1(). When I type the URL "http://10.0.0.6:8000/api/hello" I am getting the html form. But on submitting the form I am not able to go to "http://10.0.0.6:8000/api/sum".
Tried
else if(mg_http_match_uri(hm, "/api/sum"))
{
mg_http_reply(c, 200, "Content-Type: text/plain\r\n", "%s\n", "Static Content");
}
and is working fine. I suspect the problem is in getting parameter values. In Java we have request.getparameter() for getting required parameters, Do we have something like that in mongoose.
So please tell me the correct way to get parameter values in a URL.
The problem is that you're submitting a form via GET, e.g. parameters are passed in the query string (in the URL). And you're getting parameters from the body.
There are two ways to fix your code.
Submit parameters in the HTTP body. To do that, change your form's method from GET to POST.
OR, get parameters from the query string. To do that, change struct mg_str params = hm->body; to struct mg_str params = hm->query;
Hope that helps.
I use springdoc-openapi-ui:1.6.9 to generate documentation, and I have this controller:
#Operation(summary = "Get a file meta by its ID")
#ApiResponses({
#ApiResponse(responseCode = "200", content = {
#Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = #Schema(implementation = FileMetaResponse.class))
}),
#ApiResponse(responseCode = "404", description = "Not found", content = {
#Content(mediaType = MediaType.TEXT_PLAIN_VALUE,
schema = #Schema(implementation = String.class))
})
})
#RequestMapping(value = "/files/meta", method = RequestMethod.GET)
public ResponseEntity<Object> getFileMate(#RequestParam final #NotEmpty String id) {
OssFile ossFIle = fileService.findFileById(UUID.fromString(id));
if (ossFIle == null) {
return new ResponseEntity<>("File not found", HttpStatus.NOT_FOUND);
}
FileMetaResponse body = new FileMetaResponse();
BeanUtils.copyProperties(ossFIle, body);
return new ResponseEntity<>(body, HttpStatus.OK);
}
But, I always got code 200 and no response body When I execute a request to this API with any id. By debugging code, I found that this request didn't arrive to backend. ui shows:
enter image description here
However, it works normally when I delete response mediatype definition, as follows:
/**
* Get a file meta by given a file ID.
*
* #param id file uuid
* #return a found OssFile meta if successful
*/
#Operation(summary = "Get a file meta by its ID")
#ApiResponses({
#ApiResponse(responseCode = "200", content = {
#Content(
schema = #Schema(implementation = FileMetaResponse.class))
}),
#ApiResponse(responseCode = "404", description = "Not found", content = {
#Content(
schema = #Schema(implementation = String.class))
})
})
#RequestMapping(value = "/files/meta", method = RequestMethod.GET)
public ResponseEntity<Object> getFileMate(#RequestParam final #NotEmpty String id) {
OssFile ossFIle = fileService.findFileById(UUID.fromString(id));
if (ossFIle == null) {
return new ResponseEntity<>("File not found", HttpStatus.NOT_FOUND);
}
FileMetaResponse body = new FileMetaResponse();
BeanUtils.copyProperties(ossFIle, body);
return new ResponseEntity<>(body, HttpStatus.OK);
}
By comparing the two requests, the Accept field of request header is different: the accept is application/json when media type is defined, otherwise the accept is */*.
If I want to define response media type and execute request on swagger-ui web, How should I do?
I want to import data from Excel files into SQL Server. The size of the file is 22 MB and contains approximately 1 million rows, but I get the error timeout.
This is the code of my controller
[System.Web.Http.Route("UploadExcel")]
[System.Web.Http.HttpPost]
[RequestFormLimits(MultipartBodyLengthLimit = 409715200)]
[RequestSizeLimit(409715200)]
public string ExcelUpload()
{
string message = "";
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
using (AngularDBEntities objEntity = new AngularDBEntities())
{
if (httpRequest.Files.Count > 0)
{
HttpPostedFile file = httpRequest.Files[0];
Stream stream = file.InputStream;
IExcelDataReader reader = null;
if (file.FileName.EndsWith(".xls"))
{
reader = ExcelReaderFactory.CreateBinaryReader(stream);
}
else if (file.FileName.EndsWith(".xlsx"))
{
reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
}
else
{
message = "This file format is not supported";
}
DataSet excelRecords = reader.AsDataSet();
reader.Close();
var finalRecords = excelRecords.Tables[0];
for (int i = 0; i < finalRecords.Rows.Count; i++)
{
UserDetail objUser = new UserDetail();
objUser.UserName = finalRecords.Rows[i][0].ToString();
objUser.EmailId = finalRecords.Rows[i][1].ToString();
objUser.Gender = finalRecords.Rows[i][2].ToString();
objUser.Address = finalRecords.Rows[i][3].ToString();
objUser.MobileNo = finalRecords.Rows[i][4].ToString();
objUser.PinCode = finalRecords.Rows[i][5].ToString();
objEntity.UserDetails.Add(objUser);
}
int output = objEntity.SaveChanges();
if (output > 0)
{
message = "Excel file has been successfully uploaded";
}
else
{
message = "Excel file uploaded failed";
}
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
return message;
}
I added maxRequestLength="1048576" executionTimeout="999999" to the web.config file in the system.web section, and maxAllowedContentLength="1073741824" to security tag, but I am still facing this problem.
Knowing that when I upload small files, the data is added to the table
you can add all items in a list and finally use bulk insert. use can use Entity Framework Extensions.
I have a Spring Boot Rest End Point defined in an interface to download an image
#GetMapping(value = "/{name}")
ResponseEntity<ByteArrayResource> getFileByName(#PathVariable("name") String name);
And I use Feign Builder to invoke this end point.
Feign.builder()
.client(new ApacheHttpClient())
.contract(new SpringMvcContract())
.decoder(new JacksonDecoder())
.encoder(new JacksonEncoder())
.target(clazz, url)
On invoking, I get below error
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('�' (code 65533 / 0xfffd)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: (BufferedReader); line: 1, column: 2]
When I try to invoke the end point directly from Insomnia, it works fine. But fails through Feign Builder. The response content type is image/jpeg
Is there any specific decoder in feign to handle ByteArrayResource? I tried ResponseEntityDecoder, StreamDecoder and JacksonDecoder. None of it works.
On debugging, I see that Jackson ObjectMapper readValue fails. I tried changing the return type from ByteArraySource to byte[], didn't work either.
Any help?
I wrote my own little decoder and the problem was resolved. Below is the decoder
private Decoder byteArrayResourceDecoder() {
Decoder decoder = (response, type) -> {
if (type instanceof Class && ByteArrayResource.class.isAssignableFrom((Class) type)) {
return StreamUtils.copyToByteArray(response.body().asInputStream());
}
return new JacksonDecoder().decode(response, type);
};
return new ResponseEntityDecoder(decoder);
}
Hope this template helps others who has similar issues. Would have expected Feign to have decoder that supports all return types.
Thanks Maz - your solution helped me.
I modified your solution for my needs to read Spring StreamingResponseBody
1.) Create the decoder wrapper that either returns JacksonDecoder (Default) or reads the responsebody into a byte array.
Decoder decoder = (response, type) -> {
Map<String, Collection<String>> headers = response.headers();
Collection<String> contentType = null;
for (String x : headers.keySet()){
if ("content-type".equals(x.toLowerCase())){
contentType = headers.get(x);
}
}
if (contentType == null || contentType.stream().filter(x -> x.contains("application/json")).findFirst().isPresent()) {
return new JacksonDecoder(getMapper()).decode(response, type);
}
InputStream initialStream = response.body().asInputStream();
byte[] buffer = new byte[512];
byte[] result = null;
try(ByteArrayOutputStream out = new ByteArrayOutputStream()) {
try {
int length = 0;
while ((length = initialStream.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
} finally {
out.flush();
}
result = out.toByteArray();
} finally {
initialStream.close();
}
return result;
};
2.) Use the custom decoder with the Feign.Builder
Feign.Builder builder = Feign.builder()
// --
.decoder(decoder)
// --
openfeignfeignspringstreamingresponsebody
I am making a rest API call using Angular. My Rest API look like as below:
#RequestMapping(value = "/getPDF/{projectId}", method = RequestMethod.POST)
public ResponseEntity<byte[]> generateReport(#PathVariable("projectId") long projectId, #RequestBody Object vo, final HttpServletRequest request) {
vo.setProjectId(projectId);
byte[] pdf = blueprintService.generateBluePrint(vo);
LOG.debug(new StringBuilder("Generating Blueprint for VO: ").append(vo).toString());
String fileName = null;
try {
ProjectDetailsVO pdvo = projectSetupService.getProjectDetails(vo.getProjectId());
fileName = new StringBuilder(pdvo.getClientName()).append("_")
.append(pdvo.getProjectName()).append("_")
.append(System.currentTimeMillis()).append(".pdf")
.toString();
} catch (Exception e) {
}
if (fileName == null || fileName.trim().isEmpty())
fileName = new StringBuilder("Project_")
.append(vo.getProjectId()).append("_")
.append(System.currentTimeMillis())
.append(".pdf").toString();
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/pdf");
String userAgent = request.getHeader("User-Agent");
if (userAgent != null && !(userAgent.contains("Firefox") && userAgent.contains("Mac"))) {
LOG.debug("Inline BP Content");
headers.add("Content-Disposition", new StringBuilder("inline; filename=\"").append(fileName).append("\"").toString());
} else {
LOG.debug("Attached BP Content");
headers.add("Content-Disposition", new StringBuilder("attachment; filename=\"").append(fileName).append("\"").toString());
}
if (pdf != null)
headers.setContentLength(pdf.length);
return new ResponseEntity<byte[]>(pdf, headers, HttpStatus.OK);
}
}
So server is setting file name for the PDF which I want to be the name of the generated PDF.
I tried below angular code:
success: function (data, status, headers, config) {
$modalInstance.close();
var file = new Blob([data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
It works fine but it open the pdf of it's own name. Which I think, since Angular is converting the response into PDF. Hence Headers are getting excluded.
Is there any way to make a post request so it will open a PDF in new browser tab some code like as below:
$http.post{
url: myRestURL,
data: postbodyData,
taget: _blank
}
which will open my rest URL in new tab and show the PDF in browser.
Thank you.