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 (body[i + j] == sep[j]) {

count++;

} else {

break;

}

}

if (count == 2) {

byte[] line = new byte[i-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 byte[end - 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_v[0])) {

paramItem.setName(k_v[1].replace("\"", ""));

} else if ("filename".equals(k_v[0])) {

paramItem.setFilename(k_v[1].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 (line[0] == sep[0] && line[1] == sep[1]) {

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 (body[i + j] == boundary[j]) {

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 +

'}';

}

}

}

相关推荐
蜗牛沐雨39 分钟前
Rust 中的 `PartialEq` 和 `Eq`:深入解析与应用
开发语言·后端·rust
Python私教40 分钟前
Rust快速入门:从零到实战指南
开发语言·后端·rust
秋野酱2 小时前
基于javaweb的SpringBoot爱游旅行平台设计和实现(源码+文档+部署讲解)
java·spring boot·后端
小明.杨2 小时前
Django 中时区的理解
后端·python·django
有梦想的攻城狮2 小时前
spring中的@Async注解详解
java·后端·spring·异步·async注解
qq_12498707532 小时前
原生小程序+springboot+vue医院医患纠纷管理系统的设计与开发(程序+论文+讲解+安装+售后)
java·数据库·spring boot·后端·小程序·毕业设计
lybugproducer3 小时前
浅谈 Redis 数据类型
java·数据库·redis·后端·链表·缓存
焚 城3 小时前
.NET8关于ORM的一次思考
后端·.net
撸猫7915 小时前
HttpSession 的运行原理
前端·后端·cookie·httpsession
嘵奇6 小时前
Spring Boot中HTTP连接池的配置与优化实践
spring boot·后端·http