html 处理HTTP请求中的multipart/form-data

siv3szwd  于 2024-01-04  发布在  其他
关注(0)|答案(1)|浏览(129)

我使用Linux套接字API实现了一个HTTP服务器,我创建的功能之一是文件传输。
我encouter的问题是当我试图传输png/jpeg文件.写入二进制文件数据后,文件被损坏,它不能被打开.对于PDF为ex.它的工作完美.
这是我处理HTTP请求的方式:
首先,我使用以下函数接收请求。这里我将接收到的缓冲区传递给HTTPrequestsException:

  1. template <typename T>
  2. void server::printReceivedData(class acceptedSocket<T> *socket)
  3. {
  4. T buffer[1025];
  5. int acceptedSocketFD = socket->getAcceptedSocketFileDescriptor();
  6. while (true)
  7. {
  8. ssize_t bytesReceived = recv(acceptedSocketFD, buffer, sizeof(buffer), 0);
  9. if (bytesReceived <= 0)
  10. {
  11. std::cerr << "Receive failed! "
  12. << socket->getError() << "\n";
  13. std::string file = __user->getFileInQueue();
  14. if (!file.empty())
  15. {
  16. addToFileTable(file.c_str(), 0);
  17. __user->clearFileInQueue();
  18. if (send(acceptedSocketFD, "HTTP/1.1 302 Found\r\nLocation: /index.html\r\nConnection: close\r\n\r\n", 65, 0) == -1)
  19. std::cerr << "Failed to send response.\n";
  20. }
  21. break;
  22. }
  23. std::cout << "\n____________________________________________________________\n\n";
  24. buffer[bytesReceived] = '\0';
  25. std::cout << buffer;
  26. HTTPrequestsHandler<T>(buffer, acceptedSocketFD, bytesReceived);
  27. }
  28. close(socket->getAcceptedSocketFileDescriptor());
  29. delete socket;
  30. }

字符串
在HTTPrequestHandle函数中,我将缓冲区转发到正确的路由函数(在本例中为**/addFileRoute**):

  1. int user::addFilesRoute(const char *buffer, int acceptedSocketFileDescriptor, ssize_t __bytesReceived)
  2. {
  3. if (findString(buffer, "filename="))
  4. {
  5. fileName.clear();
  6. path.clear();
  7. path = "interface/storage/";
  8. const std::string t_buffer = std::string(buffer);
  9. std::regex fileNameRegex(R"(filename=\"([^\"]+)\")");
  10. std::smatch match;
  11. if (std::regex_search(t_buffer, match, fileNameRegex))
  12. fileName = match.str(1);
  13. path = path + fileName;
  14. addFileInQueue(fileName);
  15. }
  16. std::ofstream file(path, std::ios::out | std::ios::app | std::ios::binary);
  17. if (file.is_open())
  18. {
  19. file.write(buffer, __bytesReceived);
  20. file.close();
  21. }
  22. return EXIT_SUCCESS;
  23. }


在这里,我用正确的文件名将文件数据写入文件中。
我添加的所有文件都成功地写入了我计算机上的一个文件,但图像文件无法打开。

addFileInQueue=准备文件名推送到数据库的函数
filename=保存当前HTTP请求的文件名的全局变量
path=用于将文件保存到正确位置的全局变量

我尝试了不同的方法来格式化文件数据。一种是删除所有请求中额外的头,但这会破坏所有内容。
!请记住,缓冲区有1025字节的数据块,而不是孔请求
谢谢你的帮助!

m2xkgtsf

m2xkgtsf1#

我设法解决了这个问题:
1.我修改了addFileroute函数,直接将数据写为uint8_t类型(我将去掉**char buffer*,只在本地重新转换)

  1. int user::addFilesRoute(const char *buffer, const uint8_t *byteBuffer, int acceptedSocketFileDescriptor, ssize_t __bytesReceived)
  2. {
  3. if (findString(buffer, "filename="))
  4. {
  5. fileName.clear();
  6. const std::string t_buffer = std::string(buffer);
  7. std::regex fileNameRegex(R"(filename=\"([^\"]+)\")");
  8. std::smatch match;
  9. if (std::regex_search(t_buffer, match, fileNameRegex))
  10. fileName = match.str(1);
  11. addFileInQueue(fileName);
  12. }
  13. FILE *file = fopen("interface/storage/temp.bin", "ab");
  14. if (file != NULL)
  15. {
  16. fwrite(byteBuffer, sizeof(uint8_t), __bytesReceived, file);
  17. fclose(file);
  18. }
  19. else
  20. {
  21. std::cerr << "Failed to open file!\n";
  22. return EXIT_FAILURE;
  23. }
  24. return EXIT_SUCCESS;
  25. }

字符串
1.我将数据写入一个temp.bin文件,在收到请求后,我处理它。(最后我删除temp.bin文件)

  1. int server::formatFile(const std::string fileName)
  2. {
  3. std::ifstream file("interface/storage/temp.bin", std::ios::binary);
  4. std::ofstream outFile("interface/storage/" + fileName, std::ios::binary);
  5. if (!file.is_open() || !outFile.is_open())
  6. {
  7. std::cout << "Error opening files!" << std::endl;
  8. return EXIT_FAILURE;
  9. }
  10. std::string line;
  11. std::string boundary = "------WebKitFormBoundary";
  12. std::string contentStart = "Content-Type:";
  13. bool foundBoundary = false;
  14. while (std::getline(file, line))
  15. {
  16. if (!foundBoundary && line.find(boundary) != std::string::npos)
  17. {
  18. foundBoundary = true;
  19. continue;
  20. }
  21. if (foundBoundary)
  22. if (line.find(contentStart) != std::string::npos)
  23. {
  24. std::getline(file, line);
  25. while (std::getline(file, line))
  26. {
  27. if (line.find(boundary) != std::string::npos)
  28. break;
  29. outFile << line << std::endl;
  30. }
  31. break;
  32. }
  33. }
  34. file.close();
  35. outFile.close();
  36. if (remove("interface/storage/temp.bin") != 0)
  37. std::cerr << "Failed to removed temp.bin!\n";
  38. return EXIT_SUCCESS;
  39. }

展开查看全部

相关问题