form表单get提交参考之前文章Chromium 前端form表单提交过程分析c++-CSDN博客
一、表单post提交测试例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h2>表单</h2>
<form action="/" method="post">
<!-- 文本输入框 -->
<label for="name">用户名:</label>
<input type="text" id="name" name="name" required>
<br>
<!-- 密码输入框 -->
<label for="password">密码:</label>
<input type="password" id="password" name="password" required>
<br>
<!-- 单选按钮 -->
<label>性别:</label>
<input type="radio" id="male" name="gender" value="male" checked>
<label for="male">男</label>
<input type="radio" id="female" name="gender" value="female">
<label for="female">女</label>
<br>
<!-- 复选框 -->
<input type="checkbox" id="subscribe" name="subscribe" checked>
<label for="subscribe">订阅推送信息</label>
<br>
<!-- 下拉列表 -->
<label for="country">国家:</label>
<select id="country" name="country">
<option value="cn">CN</option>
<option value="usa">USA</option>
<option value="uk">UK</option>
</select>
<br>
<!-- 提交按钮 -->
<input type="submit" value="提交">
</form>
</body>
</html>
二、启动调试打开测试页:
在\src\third_party\blink\renderer\core\loader\form_submission.cc
FormSubmission::Create函数打断点:
1.1)、 FormSubmission::Attributes copied_attributes;
copied_attributes.CopyFrom(attributes);
获取前端:
名称 | 值 | 类型 | |
---|---|---|---|
◢ | copied_attributes | {method_=kPostMethod (1) is_multi_part_form_=false action_=[1] "/" ...} | blink::FormSubmission::Attributes |
method_ | kPostMethod (1) | blink::FormSubmission::SubmitMethod | |
is_multi_part_form_ | false | bool | |
▶ action_ | [1] "/" | WTF::String | |
▶ target_ | (null) | WTF::AtomicString | |
▶ encoding_type_ | [33] "application/x-www-form-urlencoded" | WTF::AtomicString | |
▶ accept_charset_ | (null) | WTF::String |
1.2)、 FormData* dom_form_data = form->ConstructEntryList(
submit_button, data_encoding.EncodingForFormSubmission());
DCHECK(dom_form_data);函数遍历form表单input属性 构建key=value
1.3)、调用form_data = dom_form_data->EncodeFormData()进行EncodeFormData
1.4)、将构造好的数据form_data设置到请求body里面:
resource_request->SetHttpMethod(http_names::kPOST);
resource_request->SetHttpBody(form_data);
看下设置到body中的值:
名称 | 值 | 类型 | |
---|---|---|---|
▶ | form_body.ptr_->elements_.buffer_[0].data_ | [60] 0x000005500040df40 "name"... | WTF::Vector<char,0,WTF::PartitionAllocator> |
form_body.ptr_->elements_.buffer_[0].data_内存地址0x000005500040df40对应值如下:
已经将刚才填写的内容设置到body。
三、wireshark抓包验证:
可以看到和调试的一样结果:
四、结论:
1.application/x-www-form-urlencoded
- GET方式,会将表单中的数据(键值对)经过urlencode编码后追加到url中。
- POST方式,会将表单中的数据经过urlencode编码后放在request body 中。
2.multipart/form-data
当需要在表单内上传文件时(二进制流数据)时,就需要使用 multipart/form-data。
附:FormSubmission::Create函数定义如下
FormSubmission* FormSubmission::Create(HTMLFormElement* form,
const Attributes& attributes,
const Event* event,
HTMLFormControlElement* submit_button) {
DCHECK(form);
FormSubmission::Attributes copied_attributes;
copied_attributes.CopyFrom(attributes);
if (submit_button) {
AtomicString attribute_value;
if (!(attribute_value =
submit_button->FastGetAttribute(html_names::kFormactionAttr))
.IsNull())
copied_attributes.ParseAction(attribute_value);
if (!(attribute_value =
submit_button->FastGetAttribute(html_names::kFormenctypeAttr))
.IsNull())
copied_attributes.UpdateEncodingType(attribute_value);
if (!(attribute_value =
submit_button->FastGetAttribute(html_names::kFormmethodAttr))
.IsNull())
copied_attributes.UpdateMethodType(attribute_value);
if (!(attribute_value =
submit_button->FastGetAttribute(html_names::kFormtargetAttr))
.IsNull())
copied_attributes.SetTarget(attribute_value);
}
if (copied_attributes.Method() == kDialogMethod) {
if (submit_button) {
return MakeGarbageCollected<FormSubmission>(
submit_button->ResultForDialogSubmit());
}
return MakeGarbageCollected<FormSubmission>("");
}
Document& document = form->GetDocument();
KURL action_url = document.CompleteURL(copied_attributes.Action().empty()
? document.Url().GetString()
: copied_attributes.Action());
if ((document.domWindow()->GetSecurityContext().GetInsecureRequestPolicy() &
mojom::blink::InsecureRequestPolicy::kUpgradeInsecureRequests) !=
mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone &&
action_url.ProtocolIs("http") &&
!network::IsUrlPotentiallyTrustworthy(GURL(action_url))) {
UseCounter::Count(document,
WebFeature::kUpgradeInsecureRequestsUpgradedRequestForm);
action_url.SetProtocol("https");
if (action_url.Port() == 80)
action_url.SetPort(443);
}
bool is_mailto_form = action_url.ProtocolIs("mailto");
bool is_multi_part_form = false;
AtomicString encoding_type = copied_attributes.EncodingType();
if (copied_attributes.Method() == kPostMethod) {
is_multi_part_form = copied_attributes.IsMultiPartForm();
if (is_multi_part_form && is_mailto_form) {
encoding_type = AtomicString("application/x-www-form-urlencoded");
is_multi_part_form = false;
}
}
WTF::TextEncoding data_encoding =
is_mailto_form
? UTF8Encoding()
: FormDataEncoder::EncodingFromAcceptCharset(
copied_attributes.AcceptCharset(), document.Encoding());
FormData* dom_form_data = form->ConstructEntryList(
submit_button, data_encoding.EncodingForFormSubmission());
DCHECK(dom_form_data);
scoped_refptr<EncodedFormData> form_data;
String boundary;
if (is_multi_part_form) {
form_data = dom_form_data->EncodeMultiPartFormData();
boundary = form_data->Boundary().data();
} else {
form_data = dom_form_data->EncodeFormData(
attributes.Method() == kGetMethod
? EncodedFormData::kFormURLEncoded
: EncodedFormData::ParseEncodingType(encoding_type));
if (copied_attributes.Method() == kPostMethod && is_mailto_form) {
// Convert the form data into a string that we put into the URL.
AppendMailtoPostFormDataToURL(action_url, *form_data, encoding_type);
form_data = EncodedFormData::Create();
}
}
form_data->SetIdentifier(GenerateFormDataIdentifier());
form_data->SetContainsPasswordData(dom_form_data->ContainsPasswordData());
if (copied_attributes.Method() != FormSubmission::kPostMethod &&
!action_url.ProtocolIsJavaScript()) {
action_url.SetQuery(form_data->FlattenToString());
}
std::unique_ptr<ResourceRequest> resource_request =
std::make_unique<ResourceRequest>(action_url);
ClientNavigationReason reason = ClientNavigationReason::kFormSubmissionGet;
if (copied_attributes.Method() == FormSubmission::kPostMethod) {
reason = ClientNavigationReason::kFormSubmissionPost;
resource_request->SetHttpMethod(http_names::kPOST);
resource_request->SetHttpBody(form_data);
// construct some user headers if necessary
if (boundary.empty()) {
resource_request->SetHTTPContentType(encoding_type);
} else {
resource_request->SetHTTPContentType(encoding_type +
"; boundary=" + boundary);
}
}
resource_request->SetHasUserGesture(
LocalFrame::HasTransientUserActivation(form->GetDocument().GetFrame()));
resource_request->SetFormSubmission(true);
mojom::blink::TriggeringEventInfo triggering_event_info;
if (event) {
triggering_event_info =
event->isTrusted()
? mojom::blink::TriggeringEventInfo::kFromTrustedEvent
: mojom::blink::TriggeringEventInfo::kFromUntrustedEvent;
if (event->UnderlyingEvent())
event = event->UnderlyingEvent();
} else {
triggering_event_info = mojom::blink::TriggeringEventInfo::kNotFromEvent;
}
FrameLoadRequest frame_request(form->GetDocument().domWindow(),
*resource_request);
NavigationPolicy navigation_policy = NavigationPolicyFromEvent(event);
if (navigation_policy == kNavigationPolicyLinkPreview) {
return nullptr;
}
frame_request.SetNavigationPolicy(navigation_policy);
frame_request.SetClientRedirectReason(reason);
if (submit_button) {
frame_request.SetSourceElement(submit_button);
} else {
frame_request.SetSourceElement(form);
}
frame_request.SetTriggeringEventInfo(triggering_event_info);
AtomicString target_or_base_target = frame_request.CleanNavigationTarget(
copied_attributes.Target().empty() ? document.BaseTarget()
: copied_attributes.Target());
if (form->HasRel(HTMLFormElement::kNoReferrer)) {
frame_request.SetNoReferrer();
frame_request.SetNoOpener();
}
if (form->HasRel(HTMLFormElement::kNoOpener) ||
(EqualIgnoringASCIICase(target_or_base_target, "_blank") &&
!form->HasRel(HTMLFormElement::kOpener) &&
form->GetDocument()
.domWindow()
->GetFrame()
->GetSettings()
->GetTargetBlankImpliesNoOpenerEnabledWillBeRemoved())) {
frame_request.SetNoOpener();
}
Frame* target_frame =
form->GetDocument()
.GetFrame()
->Tree()
.FindOrCreateFrameForNavigation(frame_request, target_or_base_target)
.frame;
// Apply replacement now, before any async steps, as the result may change.
WebFrameLoadType load_type = WebFrameLoadType::kStandard;
LocalFrame* target_local_frame = DynamicTo<LocalFrame>(target_frame);
if (target_local_frame &&
target_local_frame->NavigationShouldReplaceCurrentHistoryEntry(
frame_request, load_type)) {
load_type = WebFrameLoadType::kReplaceCurrentItem;
}
return MakeGarbageCollected<FormSubmission>(
copied_attributes.Method(), action_url, target_or_base_target,
encoding_type, frame_request.GetSourceElement(), std::move(form_data),
event, frame_request.GetNavigationPolicy(), triggering_event_info, reason,
std::move(resource_request), target_frame, load_type,
form->GetDocument().domWindow(),
form->GetDocument().GetFrame()->GetLocalFrameToken(),
CaptureSourceLocation(form->GetDocument().domWindow()),
form->GetDocument()
.domWindow()
->GetPolicyContainer()
->IssueKeepAliveHandle());
}
标签:form,Chromium,frame,request,c++,attributes,copied,data
From: https://blog.csdn.net/jangdong/article/details/143029396