I am new to winHttp / client server communication, and stuck with sending a png image to server as attachment . I created an exe using C++ just to solve this problem . Somehow I managed to hit the server , and it is giving below response ,
{"code":"9999","message":"org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'attachment' is not present","cause":".","correlationID":"***-***-43f4-82b2-***","apiURL":"POST : /file/4856.png","origin":"PartMfgServer","timestamp":1704814609769}
here is my BE code ,
@PostMapping(path = "/{fileName}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String uploadFileFromServer(@RequestHeader("File-Type") String contentType,
@PathVariable("fileName") String fileName,
@RequestParam(value = "fileRole", required = false) FILE_ROLE fileRole,
@RequestParam("attachment") MultipartFile fileToUpload)
{.......}
here is my code ,
int main() {
LPCWSTR server = L"domain.com";
LPCWSTR path = L"api/v2307/file/4856.png";
HINTERNET hSession = WinHttpOpen(L"ImageUploader/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) {
return -1;
}
HINTERNET hConnect = WinHttpConnect(hSession, server, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!hConnect) {
std::cerr << "WinHttpConnect failed!" << std::endl;
WinHttpCloseHandle(hSession);
return -1;
}
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (!hRequest) {
// Handle connection error
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
// Open image file for reading
HANDLE hFile = CreateFile(L"C:\\Users\\m5zmfk\\AppData\\Local\\Temp\\nxOpen\\partfiles\\4856\\4856.png", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
// Handle file open error
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
DWORD fileSize = GetFileSize(hFile, NULL);
std::wstring boundary = L"---------------------------1234567890";
// std::wstring endBoundary = L"\r\n--" + boundary + L"--\r\n";
std::wstring formDataBody = L"--" + boundary + L"\r\n"
L"Content-Disposition: form-data; name=\"attachment\"; filename=\"4856.png\"\r\n"
L"\r\n--" + boundary + L"--\r\n";
std::wstring headers = L"authorization: ****\r\n"
L"Content-Type: multipart/form-data; boundary=" + boundary + L"\r\n"
L"File-Type: image/png\r\n"
L"Content-Length: " + std::to_wstring(fileSize + formDataBody.length()) +L"\r\n";
bool success = WinHttpAddRequestHeaders(hRequest, headers.c_str(), headers.length(), WINHTTP_ADDREQ_FLAG_ADD);
if (!success) {
std::cout << "Error adding headers" << std::endl;
printLastError(GetLastError());
}
DWORD timeout = 60000 * 2; // Set timeout to 60 seconds (adjust as needed)
WinHttpSetOption(hRequest, WINHTTP_OPTION_RECEIVE_TIMEOUT, &timeout, sizeof(timeout));
WinHttpSetOption(hRequest, WINHTTP_OPTION_SEND_TIMEOUT, &timeout, sizeof(timeout));
if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
// Handle request send error
printLastError(GetLastError());
CloseHandle(hFile);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
DWORD bytesWritten;
// Build the form-data request body
success = WinHttpWriteData(hRequest, formDataBody.c_str(), formDataBody.length(), &bytesWritten);
if (!success) {
printLastError(GetLastError());
CloseHandle(hFile);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
// Write the file content
BYTE buffer[1024];
DWORD bytesRead;
while (ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL) && bytesRead > 0) {
success = WinHttpWriteData(hRequest, buffer, bytesRead, &bytesWritten);
if (!success) {
printLastError(GetLastError());
CloseHandle(hFile);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
}
if (!WinHttpReceiveResponse(hRequest, NULL)) {
// Handle response error
printLastError(GetLastError());
CloseHandle(hFile);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
// Read and print the response
DWORD resRead;
BYTE resBuffer[1024];
while (WinHttpReadData(hRequest, resBuffer, sizeof(resBuffer), &resRead) && resRead > 0) {
// Process the received data (you can print it or save it to a file, etc.)
std::cout.write(reinterpret_cast<const char*>(resBuffer), resRead);
}
// Close the file and WinHTTP handles
CloseHandle(hFile);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 0;
}
Can anyone help me with what is going wrong .
I tried giving formDataBody as header using WinHttpAddRequestHeaders. I got error code 87.
std::wstring formDataBody = L"--" + boundary + L"\r\n"
L"Content-Disposition: form-data; name=\"attachment\"; filename=\"4856.png\"\r\n"
L"\r\n--" + boundary + L"--\r\n";
You are not sending the PNG data correctly. It needs to be inside your
formDataBodyvariable, as the body of theattachmentMIME part, after its headers and before its closing boundary. You are sending the PNG data after all of the MIME data has been sent, which is wrong.Also, MIME is based on 7bit ASCII, so you should not be using a
std::wstringfor yourformDataBodyvariable, usestd::stringinstead (usingstd::wstringfor all of the other WinHTTP function parameters is fine).Also,
File-Typeis not a standard HTTP header. You should instead specify a standardContent-Typeheader inside theattachmentMIME part, and then have youruploadFileFromServer()handler retrieve the file type from that header (you can get it from theMultipartFile.getContentType()method).With that said, try something more like this:
If you really want to use
WinHttpWriteData()to send the PNG data in chunks, then it needs to look more like this instead: