SSI Tag的使用
这里先说最原始的使用SSI tag的方式,因为这样做在C开发中最简单。跟后来通用的web服务器的SSI有点不一样,因为后来为了使上层开发更方便,又进行了一些封装。 最原始的SSI是这样规定的,如在html中嵌入SSI tag。使用 [code]<–#tagname–>[/code] ;,则当Web服务器生成网页时,会将当前的标签后插入所指定的内容。这就是SSI Tag的作用。 SSI可以说是最初动态生成网页的方法,不仅仅是用来插入一些变量也可以直接插入javascript、json等等你想要发送给客户端的内容!一般用SSI来插入静态变量比较方便,如果是插入input框的当前值的话,可以往SSI中插入一段javascript代码或者是json格式的数据,再用javascript把这些实时的值加载进input框。 [html] Name: IP Address: MAC Address: [/html] 其Tag 在Web 服务端代码中作如下定义,并定义其序号的宏。 [c] static const char *g_pcConfigSSITags[] = { “ipaddr”, // SSI_INDEX_IPADDR “macaddr”, // SSI_INDEX_MACADDR “p0br”, // SSI_INDEX_P0BR “p0sb”, // SSI_INDEX_P0SB “p0p”, // SSI_INDEX_P0P “p0bc”, // SSI_INDEX_P0BC “p0fc”, // SSI_INDEX_P0FC “p0tt”, // SSI_INDEX_P0TT “p0tlp”, // SSI_INDEX_P0TLP “p0trp”, // SSI_INDEX_P0TRP “p0tip”, // SSI_INDEX_P0TIP “p0tip1”, // SSI_INDEX_P0TIP1 “p0tip2”, // SSI_INDEX_P0TIP2 “p0tip3”, // SSI_INDEX_P0TIP3 “p0tip4”, // SSI_INDEX_P0TIP4 “p0tnm”, // SSI_INDEX_P0TNM “p1br”, // SSI_INDEX_P1BR “p1sb”, // SSI_INDEX_P1SB “p1p”, // SSI_INDEX_P1P “p1bc”, // SSI_INDEX_P1BC “p1fc”, // SSI_INDEX_P1FC “p1tt”, // SSI_INDEX_P1TT “p1tlp”, // SSI_INDEX_P1TLP “p1trp”, // SSI_INDEX_P1TRP “p1tip”, // SSI_INDEX_P1TIP “p1tip1”, // SSI_INDEX_P1TIP1 “p1tip2”, // SSI_INDEX_P1TIP2 “p1tip3”, // SSI_INDEX_P1TIP3 “p1tip4”, // SSI_INDEX_P1TIP4 “p1tnm”, // SSI_INDEX_P1TNM “modname”, // SSI_INDEX_MODNAME “pnpport”, // SSI_INDEX_PNPPORT “disable”, // SSI_INDEX_DISABLE … }; [/c] 然后在SSIHandler里如下解析,当每次serving a page with a ``.ssi’', ``.shtml’’ or ``.shtm’’ file extension 的时候都会将SSI tag进行替换。 [c] static uint16_t ConfigSSIHandler(int iIndex, char *pcInsert, int iInsertLen) { uint32_t ui32Port; int iCount; const char *pcString; // // Which SSI tag are we being asked to provide content for? // switch(iIndex) { // // The local IP address tag “ipaddr”. // case SSI_INDEX_IPADDR: { uint32_t ui32IPAddr; ui32IPAddr = lwIPLocalIPAddrGet(); return(usnprintf(pcInsert, iInsertLen, “%d.%d.%d.%d”, ((ui32IPAddr >> 0) & 0xFF), ((ui32IPAddr >> 8) & 0xFF), ((ui32IPAddr >> 16) & 0xFF), ((ui32IPAddr >> 24) & 0xFF))); } // // The local MAC address tag “macaddr”. // case SSI_INDEX_MACADDR: { uint8_t pucMACAddr[6]; lwIPLocalMACGet(pucMACAddr); return(usnprintf(pcInsert, iInsertLen, “%02X-%02X-%02X-%02X-%02X-%02X”, pucMACAddr[0], pucMACAddr[1], pucMACAddr[2], pucMACAddr[3], pucMACAddr[4], pucMACAddr[5])); } … // // All other tags are unknown. // default: { return(usnprintf(pcInsert, iInsertLen, “Tag %d unknown!”, iIndex)); } } } [/c] 学习了SSI tag怎么用的,然后可以再深入研究下在文本中检索 SSI tag 的写法。这里用了个状态机,按顺序搜索ssi lead in 和lead out。 [c] /* We have sent all the data that was already parsed so continue parsing * the buffer contents looking for SSI tags. */ while((hs->parse_left) && (err == ERR_OK)) { /* @todo: somewhere in this loop, ‘len’ should grow again… */ if (len == 0) { return data_to_send; } switch(hs->tag_state) { case TAG_NONE: /* We are not currently processing an SSI tag so scan for the * start of the lead-in marker. */ if(*hs->parsed == g_pcTagLeadIn[0]) { /* We found what could be the lead-in for a new tag so change * state appropriately. */ hs->tag_state = TAG_LEADIN; hs->tag_index = 1; #if !LWIP_HTTPD_SSI_INCLUDE_TAG hs->tag_started = hs->parsed; #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */ } /* Move on to the next character in the buffer */ hs->parse_left–; hs->parsed++; break; case TAG_LEADIN: /* We are processing the lead-in marker, looking for the start of * the tag name. */ /* Have we reached the end of the leadin? */ if(hs->tag_index == LEN_TAG_LEAD_IN) { hs->tag_index = 0; hs->tag_state = TAG_FOUND; } else { /* Have we found the next character we expect for the tag leadin? */ if(*hs->parsed == g_pcTagLeadIn[hs->tag_index]) { /* Yes - move to the next one unless we have found the complete * leadin, in which case we start looking for the tag itself */ hs->tag_index++; } else { /* We found an unexpected character so this is not a tag. Move * back to idle state. */ hs->tag_state = TAG_NONE; } /* Move on to the next character in the buffer */ hs->parse_left–; hs->parsed++; } break; case TAG_FOUND: /* We are reading the tag name, looking for the start of the * lead-out marker and removing any whitespace found. */ /* Remove leading whitespace between the tag leading and the first * tag name character. */ if((hs->tag_index == 0) && ((*hs->parsed == ' ‘) || (*hs->parsed == ‘\t’) || (*hs->parsed == ‘\n’) || (*hs->parsed == ‘\r’))) { /* Move on to the next character in the buffer */ hs->parse_left–; hs->parsed++; break; } /* Have we found the end of the tag name? This is signalled by * us finding the first leadout character or whitespace */ if((*hs->parsed == g_pcTagLeadOut[0]) || (*hs->parsed == ' ‘) || (*hs->parsed == ‘\t’) || (*hs->parsed == ‘\n’) || (*hs->parsed == ‘\r’)) { if(hs->tag_index == 0) { /* We read a zero length tag so ignore it. */ hs->tag_state = TAG_NONE; } else { /* We read a non-empty tag so go ahead and look for the * leadout string. */ hs->tag_state = TAG_LEADOUT; LWIP_ASSERT(“hs->tag_index <= 0xff”, hs->tag_index <= 0xff); hs->tag_name_len = (u8_t)hs->tag_index; hs->tag_name[hs->tag_index] = ‘\0’; if(*hs->parsed == g_pcTagLeadOut[0]) { hs->tag_index = 1; } else { hs->tag_index = 0; } } } else { /* This character is part of the tag name so save it */ if(hs->tag_index < LWIP_HTTPD_MAX_TAG_NAME_LEN) { hs->tag_name[hs->tag_index++] = *hs->parsed; } else { /* The tag was too long so ignore it. */ hs->tag_state = TAG_NONE; } } /* Move on to the next character in the buffer */ hs->parse_left–; hs->parsed++; break; /* We are looking for the end of the lead-out marker. */ case TAG_LEADOUT: /* Remove leading whitespace between the tag leading and the first * tag leadout character. */ if((hs->tag_index == 0) && ((*hs->parsed == ' ‘) || (*hs->parsed == ‘\t’) || (*hs->parsed == ‘\n’) || (*hs->parsed == ‘\r’))) { /* Move on to the next character in the buffer */ hs->parse_left–; hs->parsed++; break; } /* Have we found the next character we expect for the tag leadout? */ if(*hs->parsed == g_pcTagLeadOut[hs->tag_index]) { /* Yes - move to the next one unless we have found the complete * leadout, in which case we need to call the client to process * the tag. */ /* Move on to the next character in the buffer */ hs->parse_left–; hs->parsed++; if(hs->tag_index == (LEN_TAG_LEAD_OUT - 1)) { /* Call the client to ask for the insert string for the * tag we just found. */ #if LWIP_HTTPD_SSI_MULTIPART hs->tag_part = 0; /* start with tag part 0 */ #endif /* LWIP_HTTPD_SSI_MULTIPART */ get_tag_insert(hs); /* Next time through, we are going to be sending data * immediately, either the end of the block we start * sending here or the insert string. */ hs->tag_index = 0; hs->tag_state = TAG_SENDING; hs->tag_end = hs->parsed; #if !LWIP_HTTPD_SSI_INCLUDE_TAG hs->parsed = hs->tag_started; #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ /* If there is any unsent data in the buffer prior to the * tag, we need to send it now. */ if (hs->tag_end > hs->file) { /* How much of the data can we send? */ #if LWIP_HTTPD_SSI_INCLUDE_TAG if(len > hs->tag_end - hs->file) { len = (u16_t)(hs->tag_end - hs->file); } #else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ if(len > hs->tag_started - hs->file) { /* we would include the tag in sending */ len = (u16_t)(hs->tag_started - hs->file); } #endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); if (err == ERR_OK) { data_to_send = true; #if !LWIP_HTTPD_SSI_INCLUDE_TAG if(hs->tag_started <= hs->file) { /* pretend to have sent the tag, too */ len += hs->tag_end - hs->tag_started; } #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ hs->file += len; hs->left -= len; } } } else { hs->tag_index++; } } else { /* We found an unexpected character so this is not a tag. Move * back to idle state. */ hs->parse_left–; hs->parsed++; hs->tag_state = TAG_NONE; } break; /* * We have found a valid tag and are in the process of sending * data as a result of that discovery. We send either remaining data * from the file prior to the insert point or the insert string itself. */ case TAG_SENDING: /* Do we have any remaining file data to send from the buffer prior * to the tag? */ if(hs->tag_end > hs->file) { /* How much of the data can we send? */ #if LWIP_HTTPD_SSI_INCLUDE_TAG if(len > hs->tag_end - hs->file) { len = (u16_t)(hs->tag_end - hs->file); } #else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ LWIP_ASSERT(“hs->started >= hs->file”, hs->tag_started >= hs->file); if (len > hs->tag_started - hs->file) { /* we would include the tag in sending */ len = (u16_t)(hs->tag_started - hs->file); } #endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ if (len != 0) { err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); } else { err = ERR_OK; } if (err == ERR_OK) { data_to_send = true; #if !LWIP_HTTPD_SSI_INCLUDE_TAG if(hs->tag_started <= hs->file) { /* pretend to have sent the tag, too */ len += hs->tag_end - hs->tag_started; } #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ hs->file += len; hs->left -= len; } } else { #if LWIP_HTTPD_SSI_MULTIPART if(hs->tag_index >= hs->tag_insert_len) { /* Did the last SSIHandler have more to send? */ if (hs->tag_part != HTTPD_LAST_TAG_PART) { /* If so, call it again */ hs->tag_index = 0; get_tag_insert(hs); } } #endif /* LWIP_HTTPD_SSI_MULTIPART */ /* Do we still have insert data left to send? */ if(hs->tag_index < hs->tag_insert_len) { /* We are sending the insert string itself. How much of the * insert can we send? */ if(len > (hs->tag_insert_len - hs->tag_index)) { len = (hs->tag_insert_len - hs->tag_index); } /* Note that we set the copy flag here since we only have a * single tag insert buffer per connection. If we don’t do * this, insert corruption can occur if more than one insert * is processed before we call tcp_output. */ err = http_write(pcb, &(hs->tag_insert[hs->tag_index]), &len, HTTP_IS_TAG_VOLATILE(hs)); if (err == ERR_OK) { data_to_send = true; hs->tag_index += len; /* Don’t return here: keep on sending data */ } } else { /* We have sent all the insert data so go back to looking for * a new tag. */ LWIP_DEBUGF(HTTPD_DEBUG, (“Everything sent.\n”)); hs->tag_index = 0; hs->tag_state = TAG_NONE; #if !LWIP_HTTPD_SSI_INCLUDE_TAG hs->parsed = hs->tag_end; #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ } break; } } } [/c] 其实看懂了SSI实现的原理,就可以联想到简单的php引擎是如何处理php代码的。另外也可以看出ssi的处理效率是比较低的,因为需要检索整个文本的ssi tag。php也类似,所以后面会出现编译型的php引擎,预先把php代码和文本分开,这样执行效率就高很多。