精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

一個(gè)影響 Node.js fs Promise API 的問題

開發(fā) 前端
Node.js 的這個(gè)問題非常久了,但是觸發(fā)概率非常小,如果大家用到權(quán)限模型且沒有開啟文件模塊權(quán)限時(shí)才會(huì)大概率觸發(fā)這個(gè)問題。

最近有用戶提交了一個(gè) issue 報(bào)告了一個(gè) Node.js 文件模塊的問題。經(jīng)過分析,發(fā)現(xiàn)這是 Node.js 文件模塊的一個(gè) Bug,并且初步看會(huì)影響大多數(shù)的 Promise API,但是幸好正常情況下并不會(huì)觸發(fā),這可能是這么多年都沒有發(fā)現(xiàn)這個(gè)問題的原因。下面介紹這個(gè)問題相關(guān)的內(nèi)容。

發(fā)現(xiàn)問題

復(fù)現(xiàn)代碼如下:

import fs from "fs"

await fs.promises.mkdtemp('asdf')

執(zhí)行 node --permission demo.mjs 預(yù)期輸出是權(quán)限相關(guān)的錯(cuò)誤,但是實(shí)際上輸出了以下錯(cuò)誤:

return await PromisePrototypeThen(
               ^
TypeError: Method Promise.prototype.then called on incompatible receiver undefined

這看起來是 Node.js 內(nèi)部的一個(gè)錯(cuò)誤。

換一個(gè)例子。

import fs from "fs"

try {
    await fs.promises.mkdtemp('asdf')
} catch(e) {
    
}

執(zhí)行 node --permission demo.mjs 預(yù)期不會(huì)報(bào)錯(cuò),但是會(huì)輸出以下錯(cuò)誤:

binding.mkdtemp(prefix, options.encoding, kUsePromises),
            ^

Error: Access to this API has been restricted. Use --allow-fs-write to manage permissions.

明明捕獲了錯(cuò)誤為什么還會(huì)輸出呢?這個(gè)信息又是哪里輸出的呢?

再看一個(gè)例子。

import fs from "fs"

process.on('unhandledRejection', () => {})
try {
    await fs.promises.mkdtemp('asdf')
} catch(e) {
    
}

再執(zhí)行 node --permission demo.mjs 就不會(huì)輸出任何錯(cuò)誤了,說明這個(gè)錯(cuò)誤是一個(gè) Rejected 的 Promise 導(dǎo)致的。

分析問題

我們看一下 mkdtemp 的實(shí)現(xiàn)來分析為什么會(huì)出現(xiàn)這個(gè)錯(cuò)誤。

async function mkdtemp(prefix, options) {
  options = getOptions(options);

  prefix = getValidatedPath(prefix, 'prefix');

  return await PromisePrototypeThen(
    binding.mkdtemp(prefix, options.encoding, kUsePromises),
    undefined,
    handleErrorFromBinding,
  );
}

上面代碼中,binding.mkdtemp 預(yù)期返回一個(gè) Promise,resolve 時(shí)什么都不做,reject 時(shí)執(zhí)行 handleErrorFromBinding,所以看起來 binding.mkdtemp 并沒有返回一個(gè) Promise,而是返回了一個(gè) undefined。接著看底層的實(shí)現(xiàn)。

static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
// 忽略不相關(guān)代碼
// 回調(diào)模式或 Promise模式
if (argc > 2) { 
    FSReqBase* req_wrap_async = GetReqWrap(args, 2);
    // 權(quán)限模型相關(guān)
    ASYNC_THROW_IF_INSUFFICIENT_PERMISSIONS(...);
    // 發(fā)起文件操作
    AsyncCall(env, req_wrap_async, ...);
  } else {  
    // 同步模式
  }
}

首先看一下 GetReqWrap。

FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args,
                      int index,
                      bool use_bigint) {
  v8::Local<v8::Value> value = args[index];
// 回調(diào)模式
if (value->IsObject()) {
    return BaseObject::Unwrap<FSReqBase>(value.As<v8::Object>());
  }

  Realm* realm = Realm::GetCurrent(args);
  BindingData* binding_data = realm->GetBindingData<BindingData>();
// Promise 模式
if (value->StrictEquals(realm->isolate_data()->fs_use_promises_symbol())) {
    if (use_bigint) {
      return FSReqPromise<AliasedBigInt64Array>::New(binding_data, use_bigint);
    } else {
      return FSReqPromise<AliasedFloat64Array>::New(binding_data, use_bigint);
    }
  }
returnnullptr;
}

GetReqWrap 的作用是創(chuàng)建一個(gè) C++ 對(duì)象,用于實(shí)現(xiàn)文件操作結(jié)束后通知 JS 層的邏輯,后面再看具體的實(shí)現(xiàn)。接著看一下 AsyncCall。

template <typename Func, typename... Args>
FSReqBase* AsyncCall(Environment* env,
                     FSReqBase* req_wrap,
                     const v8::FunctionCallbackInfo<v8::Value>& args,
                     const char* syscall, enum encoding enc,
                     uv_fs_cb after, Func fn, Args... fn_args) {
return AsyncDestCall(env, req_wrap, args,
                       syscall, nullptr, 0, enc,
                       after, fn, fn_args...);
}

template <typename Func, typename... Args>
FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap,
                         const v8::FunctionCallbackInfo<v8::Value>& args,
                         const char* syscall, const char* dest,
                         size_t len, enum encoding enc, uv_fs_cb after,
                         Func fn, Args... fn_args) {
  CHECK_NOT_NULL(req_wrap);
  req_wrap->Init(syscall, dest, len, enc);
int err = req_wrap->Dispatch(fn, fn_args..., after);
// 失敗直接通知 JS 層
if (err < 0) {
    uv_fs_t* uv_req = req_wrap->req();
    uv_req->result = err;
    uv_req->path = nullptr;
    after(uv_req);  // after may delete req_wrap if there is an error
    req_wrap = nullptr;
  } else {
    // 成功則設(shè)置返回 JS 層的值,比如返回一個(gè) Promise
    req_wrap->SetReturnValue(args);
  }

return req_wrap;
}

AsyncCall 調(diào)了 AsyncDestCall,AsyncDestCall 最終調(diào) Libuv 發(fā)起了一個(gè)文件操作,這里的情況有三種。

  1. 發(fā)起操作失敗,即 err < 0。
  2. 發(fā)起操作成功,但是執(zhí)行底層文件操作失敗,異步通知。
  3. 發(fā)起操作成功,執(zhí)行底層文件操作成功,異步通知。

正常流程是 2 或 3,所以發(fā)起文件操作成功后會(huì)先設(shè)置返回值給 JS 層。

template <typename AliasedBufferT>
void FSReqPromise<AliasedBufferT>::SetReturnValue(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Local<v8::Value> val;
  if (!object()->Get(env()->context(), env()->promise_string()).ToLocal(&val)) {
    return;
  }
  v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
  args.GetReturnValue().Set(resolver->GetPromise());
}

最終返回給 JS 的是一個(gè) Promise,JS 層會(huì) await 返回的 Promise,等到 Libuv 執(zhí)行文件操作完成后決議該 Promise。接著看文件操作結(jié)束后的處理邏輯。

void AfterStringPath(uv_fs_t* req) {
  FSReqBase* req_wrap = FSReqBase::from_req(req);
FSReqAfterScope after(req_wrap, req);
  MaybeLocal<Value> link;
// 操作失敗
if (req_->result < 0) {
    Reject(req_);
    return;
  }
// 操作成功
TryCatch try_catch(req_wrap->env()->isolate());
  link = StringBytes::Encode(...);
// 結(jié)果無效
if (link.IsEmpty()) {
    req_wrap->Reject(try_catch.Exception());
  } else {  // 結(jié)果有效
    Local<Value> val;
    if (link.ToLocal(&val)) req_wrap->Resolve(val);
  }
}

AfterStringPath 會(huì)執(zhí)行 Resolve 或 Reject,看一下 Reject 的實(shí)現(xiàn)。

template <typename AliasedBufferT>
void FSReqPromise<AliasedBufferT>::Reject(v8::Local<v8::Value> reject) {
  v8::Local<v8::Value> value;
  if (!object()
           ->Get(env()->context(), env()->promise_string())
           .ToLocal(&value)) {
    return;
  }
  v8::Local<v8::Promise::Resolver> resolver = value.As<v8::Promise::Resolver>();
  USE(resolver->Reject(env()->context(), reject).FromJust());
}

最終 Reject 了返回給 JS 層的 Promise,這時(shí)候 JS 的 await promise 就返回了。

那么問題出在哪里呢?問題出在發(fā)起文件操作的情況 1 中,也就是當(dāng)發(fā)起文件操作失敗時(shí),C++ 層沒有把 Promise 返回給 JS 層,而僅僅是在 C++ 層把這個(gè) Promise 設(shè)置為 Rejected 狀態(tài),所以導(dǎo)致了前面例子的錯(cuò)誤。那么為什么這個(gè)問題這么多年都沒有出現(xiàn)呢?因?yàn)榘l(fā)起文件操作失敗的概率非常小,下面是一種失敗的場(chǎng)景。

int uv_fs_mkdtemp(uv_loop_t* loop,
                  uv_fs_t* req,
                  const char* tpl,
                  uv_fs_cb cb) {
  INIT(MKDTEMP);
  req->path = uv__strdup(tpl);
  if (req->path == NULL)
    return UV_ENOMEM;
  POST;
}

可以看到當(dāng)沒有內(nèi)存時(shí)會(huì)導(dǎo)致發(fā)起文件操作失敗,這個(gè)概率太小了。既然難以出現(xiàn),為什么現(xiàn)在出現(xiàn)了呢?因?yàn)?Node.js 引入的權(quán)限模型以另一種方式觸發(fā)了這個(gè) Bug。看一下文件模塊中權(quán)限模型的處理邏輯(權(quán)限模型的代碼在發(fā)起文件操作之前執(zhí)行)。

ASYNC_THROW_IF_INSUFFICIENT_PERMISSIONS(
        env,
        req_wrap_async,
        permission::PermissionScope::kFileSystemWrite,
        tmpl.ToStringView());

ASYNC_THROW_IF_INSUFFICIENT_PERMISSIONS 是一個(gè)宏。

#define ASYNC_THROW_IF_INSUFFICIENT_PERMISSIONS(                               \
    env, wrap, perm_, resource_, ...)                                          \
  do {                                                                         \
    if (!env->permission()->is_granted(env, perm_, resource_)) [[unlikely]] {  \
      node::permission::Permission::AsyncThrowAccessDenied(                    \
          (env), wrap, perm_, resource_);                                      \
      return __VA_ARGS__;                                                      \
    }                                                                          \
  } while (0)

沒有權(quán)限時(shí)執(zhí)行 AsyncThrowAccessDenied。

void Permission::AsyncThrowAccessDenied(Environment* env,
                                        fs::FSReqBase* req_wrap,
                                        PermissionScope perm,
                                        const std::string_view& res) {
  Local<Value> err;
  if (CreateAccessDeniedError(env, perm, res).ToLocal(&err)) {
    return req_wrap->Reject(err);
  }
}

最終 Reject 了 Promise,但是這個(gè) Promise 并沒有返回給 JS,從而導(dǎo)致了兩個(gè)問題,第一個(gè)問題是 JS 因?yàn)?C++ 返回了 undefined 觸發(fā)了 Method Promise.prototype.then called on incompatible receiver undefined 的報(bào)錯(cuò),第二個(gè)問題是 Reject 的 Promise 無法捕獲,觸發(fā)了 unhandledRejection 事件(可能會(huì)導(dǎo)致進(jìn)程退出)。

那么為什么權(quán)限模型的單測(cè)沒有發(fā)現(xiàn)這個(gè)問題呢?首先權(quán)限模型的單測(cè)測(cè)試的場(chǎng)景大多是基于文件模塊的回調(diào)模式 API(回調(diào)模式?jīng)]有這個(gè)問題,因?yàn)樗{(diào) C++ 層時(shí)本身就不需要返回值),而基于 Promise API 的單測(cè)一共測(cè)試了 8 個(gè) API,其中 5 個(gè) API 沒有這個(gè)問題,其他 3 個(gè)觸發(fā)了這個(gè)問題,但是被注釋了。

// TODO: Uncaught Exception somehow?
// assert.rejects(async () => {
//   return fs.promises.chown(blockedFile, 1541, 999);
// }, {
//   code: 'ERR_ACCESS_DENIED',
//   permission: 'FileSystemWrite',
// });

通過分析發(fā)現(xiàn),這個(gè)問題的原因是因?yàn)?C++ 沒有設(shè)置返回值給 JS 層導(dǎo)致的,而這又是大多數(shù) Promise API 的公共邏輯,所以大多數(shù) Promise 的 API 都會(huì)受這個(gè)問題的影響,接下來看如何解決這個(gè)問題。

解決問題

我初步修復(fù)了 mkdtemp API 并驗(yàn)證成功,但是解決單個(gè) API 的問題并不難,難在解決受影響的所有 API。大致的解決思路就是在 C++ 層的每個(gè) API 核心代碼執(zhí)行前先設(shè)置給 JS 的返回值,但是這個(gè)看起來非常麻煩,經(jīng)過分析,最終發(fā)現(xiàn)在 GetReqWrap 中可以統(tǒng)一處理這個(gè)問題,修復(fù)代碼如下。

FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args,
                      int index,
                      bool use_bigint) {
  v8::Local<v8::Value> value = args[index];
  FSReqBase* result = nullptr;
if (value->IsObject()) {
    result = BaseObject::Unwrap<FSReqBase>(value.As<v8::Object>());
  } else {
    Realm* realm = Realm::GetCurrent(args);
    BindingData* binding_data = realm->GetBindingData<BindingData>();

    if (value->StrictEquals(realm->isolate_data()->fs_use_promises_symbol())) {
      if (use_bigint) {
        result =
            FSReqPromise<AliasedBigInt64Array>::New(binding_data, use_bigint);
      } else {
        result =
            FSReqPromise<AliasedFloat64Array>::New(binding_data, use_bigint);
      }
    }
  }
if (result != nullptr) {
    result->SetReturnValue(args);
  }
return result;
}

具體可以參考這個(gè) PR,但是影響面比較大,還需要 Review 和測(cè)試。

總結(jié)

Node.js 的這個(gè)問題非常久了,但是觸發(fā)概率非常小,如果大家用到權(quán)限模型且沒有開啟文件模塊權(quán)限時(shí)才會(huì)大概率觸發(fā)這個(gè)問題。

責(zé)任編輯:武曉燕 來源: 編程雜技
相關(guān)推薦

2011-10-25 09:28:30

Node.js

2020-10-29 16:00:03

Node.jsweb前端

2020-08-07 10:40:56

Node.jsexpress前端

2024-03-26 10:38:47

模塊CommonJSES

2021-09-15 19:02:42

Node.jsFs模塊

2022-09-04 15:54:10

Node.jsAPI技巧

2023-01-10 14:11:26

2022-03-08 15:13:34

Fetch APINode.js開發(fā)者

2020-11-11 10:09:06

Node.jsPromise前端

2022-06-05 13:52:32

Node.jsDNS 的原理DNS 服務(wù)器

2011-06-17 10:29:04

Nodejavascript

2024-09-25 08:04:58

2017-03-06 13:20:31

2022-01-02 06:55:08

Node.js ObjectWrapAddon

2014-08-01 10:24:11

2020-08-24 08:07:32

Node.js文件函數(shù)

2022-10-18 18:43:40

Node.js低代碼

2021-02-10 07:38:43

Node.js后端框架

2023-06-30 23:25:46

HTTP模塊內(nèi)存

2022-06-23 06:34:56

Node.js子線程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

茄子视频成人在线观看| 久久资源免费视频| 992kp快乐看片永久免费网址| 福利在线视频导航| 国产最新精品免费| 性视频1819p久久| 国产一区二区三区四区在线| 美女国产精品久久久| 欧美午夜精品伦理| 中文字幕在线中文| 国产精品久久久久一区二区国产| 国产精品一区二区视频| 国产精品白嫩美女在线观看 | 国产欧美一区二区精品久久久| 91精品国产综合久久精品性色| 欧美成人xxxxx| av网站网址在线观看| 欧美啪啪小视频| 精品网站aaa| 在线电影国产精品| 中文字幕第21页| 九色porny丨国产首页在线| 综合电影一区二区三区| 欧美日韩在线观看一区| 人妻中文字幕一区| 国产在线精品一区二区三区不卡| 日韩av免费看| 一区二区三区视频免费看| 午夜日韩在线| 精品国偷自产在线视频| 国产综合精品久久久久成人av| 国产伦精品一区二区三区免费优势| 欧美日韩三级一区| 日韩视频免费在线播放| 小草在线视频免费播放| 亚洲一区二区三区精品在线| 男人的天堂成人| 色综合久久影院| 欧美国产1区2区| 欧美一级爽aaaaa大片| 色视频在线观看| 91在线播放网址| 国产一区视频观看| 欧美自拍偷拍第一页| 高清日韩电视剧大全免费| 2020国产精品久久精品不卡| 国产毛片久久久久| 国产一区二区伦理片| 国产日韩欧美中文| 91中文字幕在线视频| 久久国产精品72免费观看| 国产免费成人av| 一卡二卡在线视频| 国产一区二区视频免费观看| 黄色亚洲大片免费在线观看| 欧美乱大交xxxxx另类电影| 国产三级国产精品国产国在线观看| 日产精品一区二区| 少妇高潮 亚洲精品| 亚洲a∨无码无在线观看| 欧美高清视频手机在在线| 日韩在线免费av| 五月天激情丁香| 欧美精品国产一区二区| 久久久久久久久久久网站| 日本三级午夜理伦三级三| 亚洲看片免费| 国产精品第一视频| 亚洲综合免费视频| 国产sm精品调教视频网站| 国产精品一 二 三| 邻居大乳一区二区三区| 国产色综合一区| 中文字幕在线中文字幕日亚韩一区| 国产激情视频在线| 天天影视涩香欲综合网| 女性隐私黄www网站视频| 成人免费一区| 日韩欧美久久久| 熟妇高潮精品一区二区三区| 国产一区二区精品久| 米奇精品一区二区三区在线观看| 日韩人妻无码一区二区三区99| 久久视频一区| 99久久精品久久久久久ai换脸| 无码国产伦一区二区三区视频| 国产日产欧美一区| 91传媒免费视频| 美女一区网站| 日韩亚洲欧美综合| 国产吞精囗交久久久| 99久久这里只有精品| 国模精品系列视频| 在线播放精品视频| 99麻豆久久久国产精品免费| 亚洲欧美电影在线观看| 国产理论在线| 欧美日韩中字一区| 国产又黄又粗又猛又爽的视频| 日韩成人影院| 51ⅴ精品国产91久久久久久| 99热精品在线播放| 国产农村妇女毛片精品久久麻豆| 久久久天堂国产精品| 姬川优奈av一区二区在线电影| 91精品国产欧美一区二区18| 免费看黄色的视频| 亚洲激情网站| 亚洲aaa激情| 成年午夜在线| 精品国产精品自拍| 毛毛毛毛毛毛毛片123| 天堂av2020| 欧美人与性动交xxⅹxx| 日韩美女一区二区三区四区| 人与嘼交av免费| 99国产精品99久久久久久粉嫩| 91久久久在线| sese一区| 在线精品视频免费播放| 久久久久亚洲av成人网人人软件| 久久综合电影| 国产成人精品免高潮在线观看| 成人午夜免费在线观看| 亚洲视频在线观看一区| 色多多视频在线播放| 欧美网色网址| 久久免费在线观看| www.av网站| 亚洲人成网站精品片在线观看| 中文久久久久久| 蜜桃一区二区| 青草热久免费精品视频| 天天干天天干天天干| 夜夜嗨av一区二区三区四季av| 色婷婷一区二区三区在线观看| 久久综合国产| 国产精品入口免费视频一| 国产在线资源| 91久久线看在观草草青青| www.久久国产| 久久婷婷av| 区一区二区三区中文字幕| 亚洲欧洲自拍| 亚洲偷欧美偷国内偷| 久久中文字幕免费| 久久久精品日韩欧美| 久章草在线视频| 一区二区三区日本久久久| 55夜色66夜色国产精品视频 | 国产91精品入口| 久操手机在线视频| 风间由美一区二区av101| 色综合天天综合网国产成人网| 国产av无码专区亚洲av| 一区二区三区不卡在线观看| 国产精品成人99一区无码| 很黄很黄激情成人| 精品亚洲一区二区三区四区五区高| a'aaa级片在线观看| 日韩电影大片中文字幕| 成人黄色激情视频| 国产精品灌醉下药二区| 色婷婷一区二区三区在线观看| 欧美国产精品| 精品国产一区二区三区麻豆小说 | 日韩精品无码一区二区三区| 黄色成人在线观看网站| 久久九九国产精品怡红院| www.久久伊人| 精品久久久国产| 亚洲а∨天堂久久精品2021| 精品亚洲成a人| 日本香蕉视频在线观看| 日韩a级大片| 国产精品久久91| 伊人222成人综合网| 日韩毛片在线观看| 国产精品天天操| 五月天久久比比资源色| 天天操天天干天天操天天干| 国产一区二区在线观看免费| 欧美久久久久久久久久久久久 | 在线观看国产精品日韩av| 国产又大又黄的视频| 亚洲国产欧美在线| 毛片aaaaaa| 国产激情一区二区三区| 免费午夜视频在线观看| 偷偷www综合久久久久久久| 国模精品娜娜一二三区| 韩日精品一区| 欧美激情国产高清| av电影在线观看| 亚洲国产女人aaa毛片在线| 国产精品欧美综合| 亚洲成人一区二区| 又色又爽的视频| 91麻豆国产福利在线观看| 中文字幕1234区| 免费亚洲视频| 人妻无码一区二区三区四区| 国产欧美日韩精品一区二区三区| 成人综合色站| 日本国产一区| 日韩av电影国产| 波多一区二区| 久久伊人精品视频| 1pondo在线播放免费| 亚洲精品少妇网址| 日韩一级免费视频| 欧美一区二区视频在线观看| 夜夜躁日日躁狠狠久久av| 精品日韩中文字幕| 久久久久久av无码免费网站| 国产精品的网站| 无码 人妻 在线 视频| 99视频精品免费视频| wwwxxx色| 国产精品99久久久久久宅男| 超碰在线97免费| 噜噜噜91成人网| 777精品久无码人妻蜜桃| 午夜国产欧美理论在线播放| 超碰成人在线免费观看| 日韩精品欧美激情一区二区| 青青草原成人| 免费成人高清在线视频theav| 国产区一区二区三区| 一区二区三区在线资源| 5566中文字幕一区二区| 美国十次综合久久| 91久色国产| 日韩中文字幕视频网| 亚洲一区二区久久久久久| 日本成人在线网站| 91亚洲精品在线观看| 日韩综合av| 亚洲va男人天堂| 韩国三级大全久久网站| 91免费电影网站| 国产精品毛片aⅴ一区二区三区| 91精品久久久久久久久久久久久| 久久久免费人体| 成人黄色在线观看| 精品久久国产一区| 99一区二区| 欧美aaaaa级| 日本免费高清一区二区| 日韩欧美视频在线播放| 超碰免费在线公开| 欧美福利在线| 亚洲熟妇国产熟妇肥婆| 久久高清免费观看| 五月婷婷六月合| 国产一区二区三区黄视频| 不卡的一区二区| 97久久超碰国产精品| 少妇毛片一区二区三区| 国产精品视频一区二区三区不卡| 国产又粗又猛又爽又黄的视频小说| 中文字幕一区二区不卡| 欧美成人国产精品高潮| 五月激情综合网| 亚洲天堂五月天| 欧美精品第1页| av中文字幕免费| 国产婷婷色综合av蜜臀av| 国产高清视频免费最新在线| 久久精品视频导航| 黄色视屏在线免费观看| 国产美女精品视频| 在这里有精品| 日韩精品久久久| 欧美在线资源| 色婷婷综合久久久久中文字幕| 麻豆成人久久精品二区三区红| 中文字幕人妻熟女人妻a片| 99精品视频在线观看| 亚洲天堂岛国片| 亚洲综合自拍偷拍| jizz国产在线| 欧美岛国在线观看| 精品资源在线看| 欧美精品激情blacked18| 快播电影网址老女人久久| 91久久国产综合久久蜜月精品| 日韩一级电影| 超碰超碰超碰超碰超碰| 快she精品国产999| 国产精品99久久久精品无码| 日本一区二区三区久久久久久久久不| 国产精品99久久久久久成人| 天天做天天摸天天爽国产一区| 97成人在线观看| 亚洲高清在线观看| 国内外激情在线| 日本免费在线精品| 97成人在线| 中文精品一区二区三区| 亚洲欧美成人| www.四虎在线| 中文字幕五月欧美| www.五月婷婷.com| 亚洲精品aⅴ中文字幕乱码| 黄色免费网站在线观看| 国产精品国产亚洲伊人久久| 精品亚洲自拍| 国产片侵犯亲女视频播放| 久久精品国产一区二区三区免费看| 亚洲最大免费视频| 亚洲综合免费观看高清在线观看| 中文字幕欧美人妻精品一区蜜臀| 日韩成人在线免费观看| 91看片在线观看| 国产成人欧美在线观看| 一级免费在线观看| 麻豆精品视频在线| 一卡二卡三卡四卡| 亚洲狠狠爱一区二区三区| 国产精品午夜福利| 中文综合在线观看| 亚洲综合在线电影| 麻豆精品传媒视频| 在线亚洲精品| 亚洲av成人片无码| 亚洲午夜久久久久久久久久久 | av一二三不卡影片| 久久香蕉精品视频| 欧美一级视频精品观看| 欧美三级黄网| 成人黄色短视频在线观看| 久久成人综合| 日韩av在线中文| 国产精品无遮挡| 伊人网免费视频| 色一区av在线| 99只有精品| 亚洲国产午夜伦理片大全在线观看网站| 久久成人亚洲| 国产ts丝袜人妖系列视频| 精品久久久久久亚洲国产300| 欧美 日韩 国产 成人 在线 91| 欧美夫妻性生活视频| 亚洲国产欧美在线观看| www.亚洲视频.com| 99久久伊人精品| 亚洲s码欧洲m码国产av| 亚洲日韩欧美视频| www.久久| 国产三级中文字幕| 国产91丝袜在线播放九色| 国产五月天婷婷| 日韩经典中文字幕| 日本中文字幕一区二区| 亚洲欧洲精品在线| 国产一二三精品| 久久伊人成人网| 亚洲精品在线视频| 免费在线观看一区| 小说区视频区图片区| 国产黑丝在线一区二区三区| 久久精品小视频| 亚洲校园激情春色| 亚洲va久久久噜噜噜久久狠狠 | 亚洲无人区码一码二码三码| 亚洲电影中文字幕在线观看| 婷婷色在线观看| 国产精品黄视频| 你懂的国产精品| 人妻丰满熟妇av无码久久洗澡| 91国产成人在线| 在线观看中文| 免费成人在线观看av| 免费成人在线影院| 免费在线观看黄色av| 亚洲精品自产拍| 亚洲精品大片| 青青草成人免费在线视频| 国产人成一区二区三区影院| 国产aⅴ爽av久久久久成人| 欧美性做爰毛片| 天天色天天射综合网| 一本色道综合久久欧美日韩精品| 欧美色欧美亚洲另类二区| segui88久久综合| 日本在线视频一区| 国产超碰在线一区| 精品一区二区无码| 欧美韩日一区二区| 精品国产一区探花在线观看 | 26uuu亚洲| 国产女人高潮时对白| 国产99久久精品一区二区 夜夜躁日日躁 | 一区二区三区精品国产| 成人av电影在线网| 国产又粗又黄又爽视频| 欧美亚洲第一区| 欧美国产免费| 中文国语毛片高清视频|