android okhttp mockserver 接收上传文件后,解析上传的文件。

Http Server 文件下载与上传,form表单字节码解析_文件传输 字节码 表单-CSDN博客

package com.feng.server.http;

import com.sun.net.httpserver.Headers;

import java.io.IOException;

import java.nio.charset.StandardCharsets;

import java.util.ArrayList;

import java.util.LinkedList;

import java.util.List;

public class HttpRequestFormResolver {

private static final int PARAM_INDEX = "Content-Disposition: form-data; ".length();

public static List<ParamItem> resolveForm(Headers headers, byte\[\] body) throws IOException {

String contentType = headers.getFirst("Content-type");

String boundary = contentType.substring(contentType.indexOf("=") + 1);

boundary = "--" + boundary; //size 52

byte\[\] boundaryBytes = boundary.getBytes(StandardCharsets.UTF_8);

List<ParamItem> paramItems = new LinkedList<>();

List<Integer> boundaryIndex = boundaryIndex(body, boundaryBytes);

int paramSize = boundaryIndex.size() - 1;

int boundaryLen = boundaryBytes.length;

byte\[\] sep = "\r\n".getBytes(StandardCharsets.UTF_8);

for (int i = 0; i < paramSize; i++) {

ParamItem paramItem = resolveParam(body, boundaryIndex.get(i)+boundaryLen+2, boundaryIndex.get(i+1), sep);

paramItems.add(paramItem);

}

return paramItems;

}

/**

* 单个参数解析

*/

private static ParamItem resolveParam(byte\[\] body, int start, int end, byte\[\] sep) {

int count = 0;

int cursor = start;

ParamItem paramItem = null;

for (int i = start; i < end; i++) {

for (int j = 0; j < 2; j++) {

if (bodyi + j == sepj) {

count++;

} else {

break;

}

}

if (count == 2) {

byte\[\] line = new bytei-cursor;

System.arraycopy(body, cursor, line, 0,i-cursor);

//参数的key value分隔符 \r\n

if (isLineBlank(line)) {

cursor = i+2;

if (paramItem == null) {

return null;

}

if (paramItem.getType().equals("text")) {

byte\[\] val = new byteend - cursor-2;

System.arraycopy(body, cursor, val, 0, end-cursor-2);

paramItem.setVal(new String(val));

} else {

paramItem.setStartIndex(cursor);

paramItem.setEndIndex(end);

}

break;

} else {

String lineStr = new String(line);

if (lineStr.startsWith("Content-Disposition: form-data; ")) {

paramItem = resolveParam(lineStr);

}

cursor = i;

}

i++;

}

count = 0;

}

return paramItem;

}

private static ParamItem resolveParam(String lineStr){

lineStr = lineStr.substring(PARAM_INDEX);

String\[\] kVs = lineStr.split(";");

ParamItem paramItem = new ParamItem();

paramItem.setType("text");

for (String kV : kVs) {

String\[\] k_v = kV.trim().split("=");

if ("name".equals(k_v0)) {

paramItem.setName(k_v1.replace("\"", ""));

} else if ("filename".equals(k_v0)) {

paramItem.setFilename(k_v1.replace("\"", ""));

paramItem.setType("file");

}

}

return paramItem;

}

private static boolean isLineBlank(byte\[\] line){

if (line.length == 0) {

return true;

}

byte\[\] sep = "\r\n".getBytes(StandardCharsets.UTF_8);

if (line.length == 2) {

if (line0 == sep0 && line1 == sep1) {

return true;

}

}

return false;

}

/**

* 索引参数的index

*/

private static List<Integer> boundaryIndex(byte\[\] body, byte\[\] boundary){

int count = 0;

List<Integer> list = new ArrayList<>();

int length = body.length;

int boundaryLen = boundary.length;

for (int i = 0; i < length; i++) {

for (int j = 0; j < boundaryLen; j++) {

if (i + j == length) {

return list;

}

if (bodyi + j == boundaryj) {

count++;

} else {

break;

}

}

if (count == boundaryLen) {

list.add(i);

i += boundaryLen - 1;

}

count = 0;

}

return list;

}

public static class ParamItem {

private String type;//text file

private String name;

private String filename;

private String val;

private int startIndex;

private int endIndex;

public String getType() {

return type;

}

public void setType(String type) {

this.type = type;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getFilename() {

return filename;

}

public void setFilename(String filename) {

this.filename = filename;

}

public String getVal() {

return val;

}

public void setVal(String val) {

this.val = val;

}

public int getStartIndex() {

return startIndex;

}

public void setStartIndex(int startIndex) {

this.startIndex = startIndex;

}

public int getEndIndex() {

return endIndex;

}

public void setEndIndex(int endIndex) {

this.endIndex = endIndex;

}

@Override

public String toString() {

return "ParamItem{" +

"type='" + type + '\'' +

", name='" + name + '\'' +

", filename='" + filename + '\'' +

", val='" + val + '\'' +

", startIndex=" + startIndex +

", endIndex=" + endIndex +

'}';

}

}

}

相关推荐
陈随易2 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
IT_陈寒5 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰5 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
用户8356290780516 小时前
Python 实现 PDF 文件加密与解密方法
后端·python
小满zs6 小时前
Go语言第二章(小无相功)
后端·go
用户8356290780516 小时前
使用 Python 冻结与拆分 Excel 窗格教程
后端·python
karry_k6 小时前
MyBatis批量insert-select踩坑:useGeneratedKeys=true 可能让PostgreSQL返回大量插入结果
java·后端
妙码生花6 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
贰先生6 小时前
Xiuno BBS X版 用户封禁系统
后端
karry_k6 小时前
PostgreSQL 在 MyBatis 中执行正常 SQL 失效:一次 DELETE USING 踩坑记录
java·后端